/-
Copyright (c) 2021 Eric Wieser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Eric Wieser

! This file was ported from Lean 3 source module algebra.group_ring_action.invariant
! leanprover-community/mathlib commit 1dac236edca9b4b6f5f00b1ad831e35f89472837
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Hom.GroupAction
import Mathbin.RingTheory.Subring.Pointwise

/-! # Subrings invariant under an action

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

section Ring

variable (M R : Type _) [Monoid M] [Ring R] [MulSemiringAction M R]

variable (S : Subring R)

open MulAction

variable {R}

#print IsInvariantSubring /-
/-- A typeclass for subrings invariant under a `mul_semiring_action`. -/
class IsInvariantSubring : Prop where
  smul_mem : ∀ (m : M) {x : R}, x ∈ S → m • x ∈ S
#align is_invariant_subring IsInvariantSubring
-/

/- warning: is_invariant_subring.to_mul_semiring_action -> IsInvariantSubring.toMulSemiringAction is a dubious translation:
lean 3 declaration is
  forall (M : Type.{u1}) {R : Type.{u2}} [_inst_1 : Monoid.{u1} M] [_inst_2 : Ring.{u2} R] [_inst_3 : MulSemiringAction.{u1, u2} M R _inst_1 (Ring.toSemiring.{u2} R _inst_2)] (S : Subring.{u2} R _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R _inst_1 _inst_2 _inst_3 S], MulSemiringAction.{u1, u2} M (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R _inst_2) R (Subring.setLike.{u2} R _inst_2)) S) _inst_1 (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R _inst_2) R (Subring.setLike.{u2} R _inst_2)) S) (Subring.toRing.{u2} R _inst_2 S))
but is expected to have type
  forall (M : Type.{u1}) {R : Type.{u2}} [_inst_1 : Monoid.{u1} M] [_inst_2 : Ring.{u2} R] [_inst_3 : MulSemiringAction.{u1, u2} M R _inst_1 (Ring.toSemiring.{u2} R _inst_2)] (S : Subring.{u2} R _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R _inst_1 _inst_2 _inst_3 S], MulSemiringAction.{u1, u2} M (Subtype.{succ u2} R (fun (x : R) => Membership.mem.{u2, u2} R (Subring.{u2} R _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R _inst_2) R (Subring.instSetLikeSubring.{u2} R _inst_2)) x S)) _inst_1 (Ring.toSemiring.{u2} (Subtype.{succ u2} R (fun (x : R) => Membership.mem.{u2, u2} R (Subring.{u2} R _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R _inst_2) R (Subring.instSetLikeSubring.{u2} R _inst_2)) x S)) (Subring.toRing.{u2} R _inst_2 S))
Case conversion may be inaccurate. Consider using '#align is_invariant_subring.to_mul_semiring_action IsInvariantSubring.toMulSemiringActionₓ'. -/
instance IsInvariantSubring.toMulSemiringAction [IsInvariantSubring M S] : MulSemiringAction M S
    where
  smul m x := ⟨m • x, IsInvariantSubring.smul_mem m x.2⟩
  one_smul s := Subtype.eq <| one_smul M s
  mul_smul m₁ m₂ s := Subtype.eq <| mul_smul m₁ m₂ s
  smul_add m s₁ s₂ := Subtype.eq <| smul_add m s₁ s₂
  smul_zero m := Subtype.eq <| smul_zero m
  smul_one m := Subtype.eq <| smul_one m
  smul_mul m s₁ s₂ := Subtype.eq <| smul_mul' m s₁ s₂
#align is_invariant_subring.to_mul_semiring_action IsInvariantSubring.toMulSemiringAction

end Ring

section

variable (M : Type _) [Monoid M]

variable {R' : Type _} [Ring R'] [MulSemiringAction M R']

variable (U : Subring R') [IsInvariantSubring M U]

/- warning: is_invariant_subring.subtype_hom -> IsInvariantSubring.subtypeHom is a dubious translation:
lean 3 declaration is
  forall (M : Type.{u1}) [_inst_1 : Monoid.{u1} M] {R' : Type.{u2}} [_inst_2 : Ring.{u2} R'] [_inst_3 : MulSemiringAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2)] (U : Subring.{u2} R' _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U], MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3
but is expected to have type
  forall (M : Type.{u1}) [_inst_1 : Monoid.{u1} M] {R' : Type.{u2}} [_inst_2 : Ring.{u2} R'] [_inst_3 : MulSemiringAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2)] (U : Subring.{u2} R' _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U], MulSemiringActionHom.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3
Case conversion may be inaccurate. Consider using '#align is_invariant_subring.subtype_hom IsInvariantSubring.subtypeHomₓ'. -/
/-- The canonical inclusion from an invariant subring. -/
def IsInvariantSubring.subtypeHom : U →+*[M] R' :=
  { U.Subtype with map_smul' := fun m s => rfl }
#align is_invariant_subring.subtype_hom IsInvariantSubring.subtypeHom

/- warning: is_invariant_subring.coe_subtype_hom -> IsInvariantSubring.coe_subtypeHom is a dubious translation:
lean 3 declaration is
  forall (M : Type.{u1}) [_inst_1 : Monoid.{u1} M] {R' : Type.{u2}} [_inst_2 : Ring.{u2} R'] [_inst_3 : MulSemiringAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2)] (U : Subring.{u2} R' _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U], Eq.{succ u2} ((fun (_x : MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) => (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) -> R') (IsInvariantSubring.subtypeHom.{u1, u2} M _inst_1 R' _inst_2 _inst_3 U _inst_4)) (coeFn.{succ u2, succ u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (fun (_x : MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) => (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) -> R') ([anonymous].{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (IsInvariantSubring.subtypeHom.{u1, u2} M _inst_1 R' _inst_2 _inst_3 U _inst_4)) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (HasLiftT.mk.{succ u2, succ u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (CoeTCₓ.coe.{succ u2, succ u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (coeBase.{succ u2, succ u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (coeSubtype.{succ u2} R' (fun (x : R') => Membership.Mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.hasMem.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) x U))))))
but is expected to have type
  forall (M : Type.{u1}) [_inst_1 : Monoid.{u1} M] {R' : Type.{u2}} [_inst_2 : Ring.{u2} R'] [_inst_3 : MulSemiringAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2)] (U : Subring.{u2} R' _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U], Eq.{succ u2} (forall (a : Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)), (fun (x._@.Mathlib.Algebra.Hom.GroupAction._hyg.2186 : Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) => R') a) (FunLike.coe.{succ u2, succ u2, succ u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (fun (_x : Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) => (fun (x._@.Mathlib.Algebra.Hom.GroupAction._hyg.2186 : Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) => R') _x) (SMulHomClass.toFunLike.{u2, u1, u2, u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) R' (SMulZeroClass.toSMul.{u1, u2} M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddMonoid.toZero.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddMonoidWithOne.toAddMonoid.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (NonAssocSemiring.toAddCommMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Semiring.toNonAssocSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U))))))) (DistribSMul.toSMulZeroClass.{u1, u2} M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddMonoid.toAddZeroClass.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddMonoidWithOne.toAddMonoid.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (NonAssocSemiring.toAddCommMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Semiring.toNonAssocSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U))))))) (DistribMulAction.toDistribSMul.{u1, u2} M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) _inst_1 (AddMonoidWithOne.toAddMonoid.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (NonAssocSemiring.toAddCommMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Semiring.toNonAssocSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)))))) (MulSemiringAction.toDistribMulAction.{u1, u2} M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) _inst_1 (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4))))) (SMulZeroClass.toSMul.{u1, u2} M R' (AddMonoid.toZero.{u2} R' (AddMonoidWithOne.toAddMonoid.{u2} R' (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} R' (NonAssocSemiring.toAddCommMonoidWithOne.{u2} R' (Semiring.toNonAssocSemiring.{u2} R' (Ring.toSemiring.{u2} R' _inst_2)))))) (DistribSMul.toSMulZeroClass.{u1, u2} M R' (AddMonoid.toAddZeroClass.{u2} R' (AddMonoidWithOne.toAddMonoid.{u2} R' (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} R' (NonAssocSemiring.toAddCommMonoidWithOne.{u2} R' (Semiring.toNonAssocSemiring.{u2} R' (Ring.toSemiring.{u2} R' _inst_2)))))) (DistribMulAction.toDistribSMul.{u1, u2} M R' _inst_1 (AddMonoidWithOne.toAddMonoid.{u2} R' (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} R' (NonAssocSemiring.toAddCommMonoidWithOne.{u2} R' (Semiring.toNonAssocSemiring.{u2} R' (Ring.toSemiring.{u2} R' _inst_2))))) (MulSemiringAction.toDistribMulAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2) _inst_3)))) (DistribMulActionHomClass.toSMulHomClass.{u2, u1, u2, u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) R' _inst_1 (AddMonoidWithOne.toAddMonoid.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (NonAssocSemiring.toAddCommMonoidWithOne.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Semiring.toNonAssocSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)))))) (AddMonoidWithOne.toAddMonoid.{u2} R' (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} R' (NonAssocSemiring.toAddCommMonoidWithOne.{u2} R' (Semiring.toNonAssocSemiring.{u2} R' (Ring.toSemiring.{u2} R' _inst_2))))) (MulSemiringAction.toDistribMulAction.{u1, u2} M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) _inst_1 (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4)) (MulSemiringAction.toDistribMulAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (MulSemiringActionHomClass.toDistribMulActionHomClass.{u2, u1, u2, u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) R' _inst_1 (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (Ring.toSemiring.{u2} R' _inst_2) (MulSemiringAction.toDistribMulAction.{u1, u2} M (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) _inst_1 (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4)) (MulSemiringAction.toDistribMulAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (MulSemiringActionHom.instMulSemiringActionHomClassMulSemiringActionHomToDistribMulActionToDistribMulAction.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3)))) (IsInvariantSubring.subtypeHom.{u1, u2} M _inst_1 R' _inst_2 _inst_3 U _inst_4)) (Subtype.val.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U))
Case conversion may be inaccurate. Consider using '#align is_invariant_subring.coe_subtype_hom IsInvariantSubring.coe_subtypeHomₓ'. -/
@[simp]
theorem IsInvariantSubring.coe_subtypeHom : (IsInvariantSubring.subtypeHom M U : U → R') = coe :=
  rfl
#align is_invariant_subring.coe_subtype_hom IsInvariantSubring.coe_subtypeHom

/- warning: is_invariant_subring.coe_subtype_hom' -> IsInvariantSubring.coe_subtypeHom' is a dubious translation:
lean 3 declaration is
  forall (M : Type.{u1}) [_inst_1 : Monoid.{u1} M] {R' : Type.{u2}} [_inst_2 : Ring.{u2} R'] [_inst_3 : MulSemiringAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2)] (U : Subring.{u2} R' _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U], Eq.{succ u2} (RingHom.{u2, u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (NonAssocRing.toNonAssocSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toNonAssocRing.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U))) (NonAssocRing.toNonAssocSemiring.{u2} R' (Ring.toNonAssocRing.{u2} R' _inst_2))) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (RingHom.{u2, u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (NonAssocRing.toNonAssocSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toNonAssocRing.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U))) (NonAssocRing.toNonAssocSemiring.{u2} R' (Ring.toNonAssocRing.{u2} R' _inst_2))) (HasLiftT.mk.{succ u2, succ u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (RingHom.{u2, u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (NonAssocRing.toNonAssocSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toNonAssocRing.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U))) (NonAssocRing.toNonAssocSemiring.{u2} R' (Ring.toNonAssocRing.{u2} R' _inst_2))) (CoeTCₓ.coe.{succ u2, succ u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (RingHom.{u2, u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (NonAssocRing.toNonAssocSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toNonAssocRing.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U))) (NonAssocRing.toNonAssocSemiring.{u2} R' (Ring.toNonAssocRing.{u2} R' _inst_2))) (RingHom.hasCoeT.{u2, u2, u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' (NonAssocRing.toNonAssocSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toNonAssocRing.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U))) (NonAssocRing.toNonAssocSemiring.{u2} R' (Ring.toNonAssocRing.{u2} R' _inst_2)) (MulSemiringActionHomClass.toRingHomClass.{u2, u1, u2, u2} (MulSemiringActionHom.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3) M (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) R' _inst_1 (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (Ring.toSemiring.{u2} R' _inst_2) (MulSemiringAction.toDistribMulAction.{u1, u2} M (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) _inst_1 (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4)) (MulSemiringAction.toDistribMulAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2) _inst_3) (MulSemiringActionHom.mulSemiringActionHomClass.{u1, u2, u2} M _inst_1 (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Ring.toSemiring.{u2} (coeSort.{succ u2, succ (succ u2)} (Subring.{u2} R' _inst_2) Type.{u2} (SetLike.hasCoeToSort.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.setLike.{u2} R' _inst_2)) U) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3))))) (IsInvariantSubring.subtypeHom.{u1, u2} M _inst_1 R' _inst_2 _inst_3 U _inst_4)) (Subring.subtype.{u2} R' _inst_2 U)
but is expected to have type
  forall (M : Type.{u1}) [_inst_1 : Monoid.{u1} M] {R' : Type.{u2}} [_inst_2 : Ring.{u2} R'] [_inst_3 : MulSemiringAction.{u1, u2} M R' _inst_1 (Ring.toSemiring.{u2} R' _inst_2)] (U : Subring.{u2} R' _inst_2) [_inst_4 : IsInvariantSubring.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U], Eq.{succ u2} (RingHom.{u2, u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) R' (Semiring.toNonAssocSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U))) (Semiring.toNonAssocSemiring.{u2} R' (Ring.toSemiring.{u2} R' _inst_2))) (MulSemiringActionHom.toRingHom.{u1, u2, u2} M _inst_1 (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Ring.toSemiring.{u2} (Subtype.{succ u2} R' (fun (x : R') => Membership.mem.{u2, u2} R' (Subring.{u2} R' _inst_2) (SetLike.instMembership.{u2, u2} (Subring.{u2} R' _inst_2) R' (Subring.instSetLikeSubring.{u2} R' _inst_2)) x U)) (Subring.toRing.{u2} R' _inst_2 U)) (IsInvariantSubring.toMulSemiringAction.{u1, u2} M R' _inst_1 _inst_2 _inst_3 U _inst_4) R' (Ring.toSemiring.{u2} R' _inst_2) _inst_3 (IsInvariantSubring.subtypeHom.{u1, u2} M _inst_1 R' _inst_2 _inst_3 U _inst_4)) (Subring.subtype.{u2} R' _inst_2 U)
Case conversion may be inaccurate. Consider using '#align is_invariant_subring.coe_subtype_hom' IsInvariantSubring.coe_subtypeHom'ₓ'. -/
@[simp]
theorem IsInvariantSubring.coe_subtypeHom' :
    (IsInvariantSubring.subtypeHom M U : U →+* R') = U.Subtype :=
  rfl
#align is_invariant_subring.coe_subtype_hom' IsInvariantSubring.coe_subtypeHom'

end


import data.real.basic

section
variables a b : ℝ

example (h : a < b) : ¬ b < a :=
begin
  intro h',
  have : a < a,
    from lt_trans h h',
  apply lt_irrefl a this,
end

def fn_ub (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, f x ≤ a
def fn_lb (f : ℝ → ℝ) (a : ℝ) : Prop := ∀ x, a ≤ f x

def fn_has_ub (f : ℝ → ℝ) := ∃ a, fn_ub f a
def fn_has_lb (f : ℝ → ℝ) := ∃ a, fn_lb f a

variable f : ℝ → ℝ

example (h : ∀ a, ∃ x, f x > a) : ¬ fn_has_ub f :=
begin
  intro fnub,
  cases fnub with a fnuba,
  cases h a with x hx,
  have : f x ≤ a,
    from fnuba x,
  linarith,
end

example (h : ∀ a, ∃ x, f x < a) : ¬ fn_has_lb f :=
begin
  rintro ⟨a, fnlba⟩,
  cases h a with x hx,
  have : f x ≥ a,
    from fnlba x,
  linarith,
end

example : ¬ fn_has_ub (λ x, x) :=
begin
  rintro ⟨a, fuba⟩,
  have : a + 1 ≤ a,
    from fuba (a + 1),
  linarith,
end

#check (not_le_of_gt : a > b → ¬ a ≤ b)
#check (not_lt_of_ge : a ≥ b → ¬ a < b)
#check (lt_of_not_ge : ¬ a ≥ b → a < b)
#check (le_of_not_gt : ¬ a > b → a ≤ b)

#print monotone
#print le_of_not_gt

example (h : monotone f) (h' : f a < f b) : a < b :=
begin
  apply lt_of_not_ge,
  intro h'',
  apply absurd h',
  apply not_lt_of_ge (h h''),
end

example (h : a ≤ b) (h' : f b < f a) : ¬ monotone f :=
begin
  intro hm,
  apply absurd h',
  apply not_lt_of_ge,
  apply hm h,
end

example :
  ¬ ∀ {f : ℝ → ℝ}, monotone f → ∀ {a b}, f a ≤ f b → a ≤ b :=
begin
  intro h,
  let f := λ x : ℝ, (0 : ℝ),
  have monof : monotone f,
  { intros a b aleb,
    linarith,},
  have h' : f 1 ≤ f 0,
    from le_refl _,
  have : (1 : ℝ) ≤ 0,
    from h monof h',
  linarith,
end

example (x : ℝ) (h : ∀ ε > 0, x < ε) : x ≤ 0 :=
begin
  apply le_of_not_gt,
  intro xle,
  have : x < x,
    from h x xle,
  linarith,
end

end

section
variables {α : Type*} (P : α → Prop) (Q : Prop)

example (h : ¬ ∃ x, P x) : ∀ x, ¬ P x :=
begin
  intros x px,
  have : ∃ x, P x := ⟨x, px⟩,
  from h this,
end

example (h : ∀ x, ¬ P x) : ¬ ∃ x, P x :=
begin
  rintro ⟨x, px⟩,
  from h x px,
end

open_locale classical

example (h : ¬ ∀ x, P x) : ∃ x, ¬ P x :=
begin
  by_contradiction hn,
  apply h,
  intro x,
  show P x,
    by_contradiction hnn,
    from hn ⟨x, hnn⟩,
end

example (h : ∃ x, ¬ P x) : ¬ ∀ x, P x :=
begin
  cases h with x npx,
  by_contradiction hn,
  from npx (hn x),
end

example (h : ¬ ¬ Q) : Q :=
begin
  by_contra hn,
  from h hn,
end

example (h : Q) : ¬ ¬ Q :=
begin
  intro hn,
  from hn h,
end

end

section
open_locale classical
variable (f : ℝ → ℝ)

example (h : ¬ fn_has_ub f) : ∀ a, ∃ x, f x > a :=
begin
  intro a,
  by_contra hn,
  apply h,
  use a,
  intro x,
  apply le_of_not_gt,
  intro fxgta,
  apply hn,
  use x,
  from fxgta,
end

example (h : ¬ ∀ a, ∃ x, f x > a) : fn_has_ub f :=
begin
  push_neg at h,
  exact h
end

example (h : ¬ fn_has_ub f) : ∀ a, ∃ x, f x > a :=
begin
  simp only [fn_has_ub, fn_ub] at h,
  push_neg at h,
  exact h
end

example (h : ¬ monotone f) : ∃ x y, x ≤ y ∧ f y < f x :=
begin
  simp only [monotone] at h,
  push_neg at h,
  exact h,
end

example (h : ¬ fn_has_ub f) : ∀ a, ∃ x, f x > a :=
begin
  contrapose! h,
  exact h
end

example (x : ℝ) (h : ∀ ε > 0, x ≤ ε) : x ≤ 0 :=
begin
  contrapose! h,
  use x / 2,
  split; linarith
end

end

variables (a : ℝ)
example (h : 0 < 0) : a > 37 :=
begin
  exfalso,
  apply lt_irrefl 0 h
end

example (h : 0 < 0) : a > 37 :=
absurd h (lt_irrefl 0)

example (h : 0 < 0) : a > 37 :=
begin
  have h' : ¬ 0 < 0,
    from lt_irrefl 0,
  contradiction
end


/-
Copyright (c) 2019 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Patrick Massot
-/
import topology.algebra.uniform_ring
import topology.algebra.field
import field_theory.subfield

/-!
# Completion of topological fields

The goal of this file is to prove the main part of Proposition 7 of Bourbaki GT III 6.8 :

The completion `hat K` of a Hausdorff topological field is a field if the image under
the mapping `x ↦ x⁻¹` of every Cauchy filter (with respect to the additive uniform structure)
which does not have a cluster point at `0` is a Cauchy filter
(with respect to the additive uniform structure).

Bourbaki does not give any detail here, he refers to the general discussion of extending
functions defined on a dense subset with values in a complete Hausdorff space. In particular
the subtlety about clustering at zero is totally left to readers.

Note that the separated completion of a non-separated topological field is the zero ring, hence
the separation assumption is needed. Indeed the kernel of the completion map is the closure of
zero which is an ideal. Hence it's either zero (and the field is separated) or the full field,
which implies one is sent to zero and the completion ring is trivial.

The main definition is `completable_top_field` which packages the assumptions as a Prop-valued
type class and the main results are the instances `uniform_space.completion.field` and
`uniform_space.completion.topological_division_ring`.
-/

noncomputable theory

open_locale classical uniformity topology

open set uniform_space uniform_space.completion filter

variables (K : Type*) [field K]  [uniform_space K]

local notation `hat` := completion

/--
A topological field is completable if it is separated and the image under
the mapping x ↦ x⁻¹ of every Cauchy filter (with respect to the additive uniform structure)
which does not have a cluster point at 0 is a Cauchy filter
(with respect to the additive uniform structure). This ensures the completion is
a field.
-/
class completable_top_field extends separated_space K : Prop :=
(nice : ∀ F : filter K, cauchy F → 𝓝 0 ⊓ F = ⊥ → cauchy (map (λ x, x⁻¹) F))

namespace uniform_space
namespace completion

@[priority 100]
instance [separated_space K] : nontrivial (hat K) :=
⟨⟨0, 1, λ h, zero_ne_one $ (uniform_embedding_coe K).inj h⟩⟩

variables {K}

/-- extension of inversion to the completion of a field. -/
def hat_inv : hat K → hat K := dense_inducing_coe.extend (λ x : K, (coe x⁻¹ : hat K))

lemma continuous_hat_inv [completable_top_field K] {x : hat K} (h : x ≠ 0) :
  continuous_at hat_inv x :=
begin
  haveI : t3_space (hat K) := completion.t3_space K,
  refine dense_inducing_coe.continuous_at_extend _,
  apply mem_of_superset (compl_singleton_mem_nhds h),
  intros y y_ne,
  rw mem_compl_singleton_iff at y_ne,
  apply complete_space.complete,
  rw ← filter.map_map,
  apply cauchy.map _ (completion.uniform_continuous_coe K),
  apply completable_top_field.nice,
  { haveI := dense_inducing_coe.comap_nhds_ne_bot y,
    apply cauchy_nhds.comap,
    { rw completion.comap_coe_eq_uniformity,
      exact le_rfl } },
  { have eq_bot : 𝓝 (0 : hat K) ⊓ 𝓝 y = ⊥,
    { by_contradiction h,
      exact y_ne (eq_of_nhds_ne_bot $ ne_bot_iff.mpr h).symm },
    erw [dense_inducing_coe.nhds_eq_comap (0 : K), ← filter.comap_inf, eq_bot],
    exact comap_bot },
end

/-
The value of `hat_inv` at zero is not really specified, although it's probably zero.
Here we explicitly enforce the `inv_zero` axiom.
-/
instance : has_inv (hat K) := ⟨λ x, if x = 0 then 0 else hat_inv x⟩

variables [topological_division_ring K]

lemma hat_inv_extends {x : K} (h : x ≠ 0) : hat_inv (x : hat K) = coe (x⁻¹ : K) :=
dense_inducing_coe.extend_eq_at
    ((continuous_coe K).continuous_at.comp (continuous_at_inv₀ h))

variables [completable_top_field K]

@[norm_cast]
lemma coe_inv (x : K) : (x : hat K)⁻¹ = ((x⁻¹ : K) : hat K) :=
begin
  by_cases h : x = 0,
  { rw [h, inv_zero],
    dsimp [has_inv.inv],
    norm_cast,
    simp },
  { conv_lhs { dsimp [has_inv.inv] },
    rw if_neg,
    { exact hat_inv_extends h },
    { exact λ H, h (dense_embedding_coe.inj H) } }
end

variables [uniform_add_group K]

lemma mul_hat_inv_cancel {x : hat K} (x_ne : x ≠ 0) : x*hat_inv x = 1 :=
begin
  haveI : t1_space (hat K) := t2_space.t1_space,
  let f := λ x : hat K, x*hat_inv x,
  let c := (coe : K → hat K),
  change f x = 1,
  have cont : continuous_at f x,
  { letI : topological_space (hat K × hat K) := prod.topological_space,
    have : continuous_at (λ y : hat K, ((y, hat_inv y) : hat K × hat K)) x,
      from continuous_id.continuous_at.prod (continuous_hat_inv x_ne),
    exact (_root_.continuous_mul.continuous_at.comp this : _) },
  have clo : x ∈ closure (c '' {0}ᶜ),
  { have := dense_inducing_coe.dense x,
    rw [← image_univ, show (univ : set K) = {0} ∪ {0}ᶜ,
                      from (union_compl_self _).symm, image_union] at this,
    apply mem_closure_of_mem_closure_union this,
    rw image_singleton,
    exact compl_singleton_mem_nhds x_ne },
  have fxclo : f x ∈ closure (f '' (c '' {0}ᶜ)) := mem_closure_image cont clo,
  have : f '' (c '' {0}ᶜ) ⊆ {1},
  { rw image_image,
    rintros _ ⟨z, z_ne, rfl⟩,
    rw mem_singleton_iff,
    rw mem_compl_singleton_iff at z_ne,
    dsimp [c, f],
    rw hat_inv_extends z_ne,
    norm_cast,
    rw mul_inv_cancel z_ne, },
  replace fxclo := closure_mono this fxclo,
  rwa [closure_singleton, mem_singleton_iff] at fxclo
end

instance : field (hat K) :=
{ exists_pair_ne := ⟨0, 1, λ h, zero_ne_one ((uniform_embedding_coe K).inj h)⟩,
  mul_inv_cancel := λ x x_ne, by { dsimp [has_inv.inv],
                                   simp [if_neg x_ne, mul_hat_inv_cancel x_ne], },
  inv_zero := show ((0 : K) : hat K)⁻¹ = ((0 : K) : hat K), by rw [coe_inv, inv_zero],
  ..completion.has_inv,
  ..(by apply_instance : comm_ring (hat K)) }

instance : topological_division_ring (hat K) :=
{ continuous_at_inv₀ := begin
    intros x x_ne,
    have : {y | hat_inv y = y⁻¹ } ∈ 𝓝 x,
    { have : {(0 : hat K)}ᶜ ⊆ {y : hat K | hat_inv y = y⁻¹ },
      { intros y y_ne,
        rw mem_compl_singleton_iff at y_ne,
        dsimp [has_inv.inv],
        rw if_neg y_ne },
      exact mem_of_superset (compl_singleton_mem_nhds x_ne) this },
    exact continuous_at.congr (continuous_hat_inv x_ne) this
  end,
  ..completion.top_ring_compl }

end completion
end uniform_space

variables (L : Type*) [field L]  [uniform_space L] [completable_top_field L]

instance subfield.completable_top_field (K : subfield L) : completable_top_field K :=
{ nice := begin
    intros F F_cau inf_F,
    let i : K →+* L := K.subtype,
    have hi : uniform_inducing i, from uniform_embedding_subtype_coe.to_uniform_inducing,
    rw ← hi.cauchy_map_iff at F_cau ⊢,
    rw [map_comm (show (i ∘ λ x, x⁻¹) = (λ x, x⁻¹) ∘ i, by {ext, refl})],
    apply completable_top_field.nice _ F_cau,
    rw [← filter.push_pull', ← map_zero i, ← hi.inducing.nhds_eq_comap, inf_F, filter.map_bot]
  end,
  ..subtype.separated_space (K : set L) }

@[priority 100]
instance completable_top_field_of_complete (L : Type*) [field L]
  [uniform_space L] [topological_division_ring L] [separated_space L] [complete_space L] :
  completable_top_field L :=
{ nice := λ F cau_F hF, begin
    haveI : ne_bot F := cau_F.1,
    rcases complete_space.complete cau_F with ⟨x, hx⟩,
    have hx' : x ≠ 0,
    { rintro rfl,
      rw inf_eq_right.mpr hx at hF,
      exact cau_F.1.ne hF },
    exact filter.tendsto.cauchy_map (calc map (λ x, x⁻¹) F ≤ map (λ x, x⁻¹) (𝓝 x) : map_mono hx
                                                       ... ≤ 𝓝 (x⁻¹) : continuous_at_inv₀ hx')
  end,
  ..‹separated_space L›}


namespace Hidden

open Nat

theorem zero_add (n : Nat) : 0 + n = n :=
  Nat.recOn (motive := fun x => 0 + x = x)
   n
   rfl
   (fun (n : Nat) (ih : 0 + n = n) =>
    show 0 + succ n = succ n from
    calc
      0 + succ n = succ (0 + n) := rfl
      _          = succ n       := by rw [ih])

end Hidden


-- Copyright (c) Microsoft Corporation. All rights reserved.
-- Licensed under the MIT license.

universes u v
-- Basic
lemma prod_inj: ∀ {α:Type u} {β:Type v} (p q:α × β),
  p = q ↔ p.fst = q.fst ∧ p.snd = q.snd
:= begin
  intros,
  split,
  { intros H, rw H, split; refl },
  { intros H, cases p, cases q, simp at H,
    cases H with H1 H2, rw [H1, H2] }
end

lemma ite_or:
  ∀ {α:Type} {c} {x y z:α} (HDEC:decidable c)
    (HITE:x = @ite c HDEC α y z),
  x = y ∨ x = z
:= begin
  intros,
  cases HDEC,
  { rw if_neg at HITE, right, assumption, assumption },
  { rw if_pos at HITE, left, assumption, assumption }
end

-- Arithmetic operations

lemma nat.pow_mul_pow: ∀ (m n:ℕ),
  m * m^n = m^(n+1)
:= begin
  intros, apply nat.mul_comm
end

lemma nat.lt_pow2: ∀ (n:ℕ),
  n < 2^n
:= begin
  intros,
  induction n,
  { simp, constructor },
  {
    have n_ih := nat.succ_lt_succ n_ih,
    apply lt_of_lt_of_le,
    { apply n_ih },
    { unfold has_pow.pow, rw nat.pow, rw nat.mul_comm, rw nat.succ_mul,
      simp, rw ← nat.add_one,
      apply nat.add_le_add_left,
      apply nat.pos_pow_of_pos, constructor, constructor
    }
  }
end

lemma nat.mod_pow2: ∀ (x:ℕ),
  x % 2^x = x
:= begin
  intros, apply nat.mod_eq_of_lt, apply nat.lt_pow2
end

lemma neq_symm: ∀ {α:Type u} (x y:α),
  x ≠ y → y ≠ x
:= begin
  intros, intros H, rw H at a, apply a, refl
end

lemma nat.not_gt_not_eq_implies_lt: ∀ (x y:ℕ),
  ¬(x > y) → (x ≠ y) → x < y
:= begin
  intros x y H1 H2,
  have H3 := nat.lt_or_ge x y,
  apply or.resolve_right,
  apply H3,
  intros H0, apply H1, apply nat.lt_of_le_and_ne, apply H0, apply neq_symm, assumption
end

-- list

lemma list.foldl_unroll: ∀ {α:Type u} {β:Type v} {f:α → β → α} a (l:list β) x,
  list.foldl f a (l++[x]) = f (list.foldl f a l) x
:= begin
  intros,
  revert a,
  induction l,
  { simp },
  { intros, simp, rw l_ih }
end

lemma list.notmem_and {α:Type u} [decidable_eq α] : ∀ (l:list α) h a,
  (a ∉ h::l) ↔ (a ≠ h ∧ a ∉ l)
:= begin
  intros,
  have HD:decidable (a ∈ l),
  { apply (list.decidable_mem a l)},
  simp, rw decidable.not_or_iff_and_not
end

lemma list.cases_back: ∀ {α:Type u} (l:list α),
  l = [] ∨ ∃ a l', l = l' ++ [a]
:= begin
  intros,
  induction l,
  { left, refl },
  {
    cases l_ih,
    {
      right,
      rw l_ih,
      apply exists.intro l_hd,
      apply exists.intro [], refl
    },
    {
      cases l_ih,
      cases l_ih_h,
      right,
      rw l_ih_h_h,
      apply exists.intro l_ih_w,
      apply exists.intro (l_hd :: l_ih_h_w),
      refl
    }
  }
end

lemma list.map_nil: ∀ {α:Type u} {β:Type v} (l:list α) (f:α → β)
  (H:list.map f l = []), l = []
:= begin
  intros,
  induction l,
  simp, simp at H, cases H
end

lemma list.map_eq: ∀ {α:Type u} {β:Type v} (l:list α) (f g:α → β)
  (H:∀ x, f x = g x),
  l.map f = l.map g
:= begin
  intros, induction l; simp [*]
end

lemma list.foldr_inv: ∀ {α:Type u} {β:Type v} (la:list α) (b:β) (f:α → β → β)
    (P:β → Prop)
    (HINV:∀ b', P b' → ∀ a', P (f a' b'))
    (H0:P b),
  P (list.foldr f b la)
:= begin
  intros,
  induction la,
  { simp, assumption },
  { simp, apply HINV, assumption }
end

lemma list.foldr_eq: ∀ {α:Type u} {β:Type v} (la1 la2:list α)
    (b1 b2:β) (f1 f2:α → β → β)
    (HF: ∀ a b, f1 a b = f2 a b)
    (HLA:la1 = la2)
    (HB: b1 = b2),
  list.foldr f1 b1 la1 = list.foldr f2 b2 la2
:= begin
  intros,
  revert la1,
  induction la2,
  { intros, subst HLA, simp, assumption },
  { intros,
    subst HLA,
    simp,
    rw la2_ih,
    apply HF, refl
  }
end

lemma list.append_eq: ∀ {α:Type u} {l l21 l22:list α},
  l ++ l21 = l ++ l22 → l21 = l22
:= begin
  intros,
  induction l, simp at a, assumption,
  apply l_ih, simp at a, assumption
end

lemma list.append_nil_eq: ∀ {α:Type u} {l l2:list α},
  l = l2 ++ l → l2 = []
:= begin
  intros, induction l with h t, simp at a, rw a,
  cases l2, refl,
  have a' : (h :: t).length = (l2_hd :: l2_tl ++ h :: t).length, rw ← a,
  simp at a',
  have a' := nat.add_left_cancel a',
  rw ← nat.add_assoc at a',
  rw nat.add_comm 1 at a',
  rw nat.add_assoc at a',
  rw ← nat.add_zero (list.length t) at a',
  have a' := nat.add_left_cancel a',
  rw nat.one_add at a', cases a'
end

lemma list.append_eq2: ∀ {α:Type u} {l l1 l2:list α},
  l1 ++ l = l2 ++ l → l1 = l2
:= begin
  intros,
  revert l2,
  induction l1, intros, simp at a, rw list.append_nil_eq a,
  intros, cases l2,
  rw list.nil_append at a, have a' := list.append_nil_eq (eq.symm a), assumption,
  injection a, rw h_1, rw l1_ih, apply h_2
end

inductive list.unique {α:Type u}: list α → Prop
| nil: list.unique []
| cons: ∀ a l (H:list.unique l) (H2:a ∉ l), list.unique (a::l)

lemma list.not_mem_append: ∀ {α:Type u} {a} {l1 l2:list α}
  (H1: a ∉ l1) (H2: a ∉ l2), a ∉ (l1 ++ l2)
:= begin
  intros, intros H0, rw list.mem_append at H0,
  cases H0, apply H1, assumption, apply H2, assumption
end

-- if two lists are different, appended lists are always different
lemma list.append_ne {α:Type u}:
  ∀ {s1 s2:list α} {a1 a2:α} (H:a1 ≠ a2),
  s1 ++ [a1] ≠ s2 ++ [a2]
:= begin
  intros, revert s2,
  induction s1,
  {
    intros, cases s2, simp, assumption,
    simp, intros H, cases H, cases s2_tl,
    simp at H_right, assumption, cases H_right
  },
  {
    intros, intros H, cases s2, simp at H,
    cases H, cases s1_tl, simp at H_right, assumption,
    simp at H_right, assumption,
    apply s1_ih, simp at H, cases H, assumption
  }
end

-- strings

def string.reverse (s:string):string := s.to_list.reverse.as_string

lemma string.append_to_list: ∀ {s1 s2:string},
  (s1 ++ s2).to_list = s1.to_list ++ s2.to_list
:= begin
  intros,
  cases s1, cases s2,
  unfold string.to_list,
  refl
end

lemma string.eq_list: ∀ {s1 s2:string},
  s1 = s2 ↔ s1.to_list = s2.to_list
:= begin
  intros,
  split,
  intros,
  cases s1, cases s2,
  injection a,
  intros, cases s1, cases s2, unfold string.to_list at a, rw a
end

lemma string.eq_suffix: ∀ {s1 s2 suffix:string}
  (H:s1 ++ suffix = s2 ++ suffix), s1 = s2
:= begin
  intros,
  rw string.eq_list at H,
  rw string.append_to_list at H,
  rw string.append_to_list at H,
  have H := list.append_eq2 H,
  rw string.eq_list,
  assumption
end

lemma string.eq_prefix: ∀ {s1 s2 pref:string}
  (H:pref++s1 = pref++s2), s1 = s2
:= begin
  intros,
  rw string.eq_list at H,
  rw string.append_to_list at H,
  rw string.append_to_list at H,
  have H := list.append_eq H,
  rw string.eq_list,
  assumption
end

lemma slist_prefix_notin: ∀ {l: list string} {a} (pref: string)
  (H:a ∉ l), pref ++ a ∉ l.map (λs, pref ++ s)
:= begin
  intros,
  intros H',
  apply H, clear H,
  induction l with h t, simp at H', cases H',
  simp at *,
  cases H', left, apply string.eq_prefix, assumption,
  right, apply l_ih, assumption
end

-- Just a special case - if first characters of two prefixes are
-- different, ∉ holds.
lemma slist_prefix_notin2: ∀ {l: list string} {a}
    (pfx1 pfx2: string) {pfx1_t pfx2_t: list char} (pfx1_h pfx2_h : char)
    (H:a ∉ l) (HNE:pfx1_h ≠ pfx2_h)
    (H1:pfx1 = (pfx1_h::pfx1_t).as_string)
    (H1:pfx2 = (pfx2_h::pfx2_t).as_string),
  pfx1 ++ a ∉ l.map (λs, pfx2 ++ s)
:= begin
  intros,
  induction l with h t,
  { simp },
  rw list.map,
  intros H0, apply l_ih,
  { intros H', apply H, simp, right, assumption },
  simp at H0,
  cases H0,
  {
    rw string.eq_list at H0,
    rw string.append_to_list at H0,
    rw string.append_to_list at H0,
    rw [H1, H1_1] at H0,
    unfold list.as_string at H0,
    unfold string.to_list at H0,
    simp at H0, cases H0, exfalso, apply HNE, assumption
  }, apply H0
end

lemma slist_prefix_unique: ∀ (l: list string) (pref: string)
  (H:list.unique l), list.unique (l.map (λs, pref ++ s))
:= begin
  intros,
  induction l with h t,
  { apply H },
  {
    cases H, have H := l_ih H_H,
    apply list.unique.cons, assumption,
    simp, apply slist_prefix_notin, assumption
  }
end


/-
Copyright (c) 2021 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import data.vector.basic
import data.list.zip

/-!
# The `zip_with` operation on vectors.
-/

namespace vector

section zip_with

variables {α β γ : Type*} {n : ℕ} (f : α → β → γ)

/-- Apply the function `f : α → β → γ` to each corresponding pair of elements from two vectors. -/
def zip_with : vector α n → vector β n → vector γ n :=
λ x y, ⟨list.zip_with f x.1 y.1, by simp⟩

@[simp]
lemma zip_with_to_list (x : vector α n) (y : vector β n) :
  (vector.zip_with f x y).to_list = list.zip_with f x.to_list y.to_list :=
rfl

@[simp]
lemma zip_with_nth (x : vector α n) (y : vector β n) (i) :
  (vector.zip_with f x y).nth i = f (x.nth i) (y.nth i) :=
begin
  dsimp only [vector.zip_with, vector.nth],
  cases x, cases y,
  simp only [list.nth_le_zip_with, subtype.coe_mk],
  congr,
end

@[simp]
lemma zip_with_tail (x : vector α n) (y : vector β n) :
  (vector.zip_with f x y).tail = vector.zip_with f x.tail y.tail :=
by { ext, simp [nth_tail], }

@[to_additive]
lemma prod_mul_prod_eq_prod_zip_with [comm_monoid α] (x y : vector α n) :
  x.to_list.prod * y.to_list.prod = (vector.zip_with (*) x y).to_list.prod :=
list.prod_mul_prod_eq_prod_zip_with_of_length_eq x.to_list y.to_list
  ((to_list_length x).trans (to_list_length y).symm)

end zip_with

end vector


/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Jeremy Avigad, Yury Kudryashov
-/
import order.filter.at_top_bot
import order.filter.pi

/-!
# The cofinite filter

In this file we define

`cofinite`: the filter of sets with finite complement

and prove its basic properties. In particular, we prove that for `ℕ` it is equal to `at_top`.

## TODO

Define filters for other cardinalities of the complement.
-/

open set function
open_locale classical

variables {α : Type*}

namespace filter

/-- The cofinite filter is the filter of subsets whose complements are finite. -/
def cofinite : filter α :=
{ sets             := {s | finite sᶜ},
  univ_sets        := by simp only [compl_univ, finite_empty, mem_set_of_eq],
  sets_of_superset := assume s t (hs : finite sᶜ) (st: s ⊆ t),
    hs.subset $ compl_subset_compl.2 st,
  inter_sets       := assume s t (hs : finite sᶜ) (ht : finite (tᶜ)),
    by simp only [compl_inter, finite.union, ht, hs, mem_set_of_eq] }

@[simp] lemma mem_cofinite {s : set α} : s ∈ (@cofinite α) ↔ finite sᶜ := iff.rfl

@[simp] lemma eventually_cofinite {p : α → Prop} :
  (∀ᶠ x in cofinite, p x) ↔ finite {x | ¬p x} := iff.rfl

lemma has_basis_cofinite : has_basis cofinite (λ s : set α, s.finite) compl :=
⟨λ s, ⟨λ h, ⟨sᶜ, h, (compl_compl s).subset⟩, λ ⟨t, htf, hts⟩, htf.subset $ compl_subset_comm.2 hts⟩⟩

instance cofinite_ne_bot [infinite α] : ne_bot (@cofinite α) :=
has_basis_cofinite.ne_bot_iff.2 $ λ s hs, hs.infinite_compl.nonempty

lemma frequently_cofinite_iff_infinite {p : α → Prop} :
  (∃ᶠ x in cofinite, p x) ↔ set.infinite {x | p x} :=
by simp only [filter.frequently, filter.eventually, mem_cofinite, compl_set_of, not_not,
  set.infinite]

/-- The coproduct of the cofinite filters on two types is the cofinite filter on their product. -/
lemma coprod_cofinite {β : Type*} :
  (cofinite : filter α).coprod (cofinite : filter β) = cofinite :=
begin
  ext S,
  simp only [mem_coprod_iff, exists_prop, mem_comap, mem_cofinite],
  split,
  { rintro ⟨⟨A, hAf, hAS⟩, B, hBf, hBS⟩,
    rw [← compl_subset_compl, ← preimage_compl] at hAS hBS,
    exact (hAf.prod hBf).subset (subset_inter hAS hBS) },
  { intro hS,
    refine ⟨⟨(prod.fst '' Sᶜ)ᶜ, _, _⟩, ⟨(prod.snd '' Sᶜ)ᶜ, _, _⟩⟩,
    { simpa using hS.image prod.fst },
    { simpa [compl_subset_comm] using subset_preimage_image prod.fst Sᶜ },
    { simpa using hS.image prod.snd },
    { simpa [compl_subset_comm] using subset_preimage_image prod.snd Sᶜ } },
end

/-- Finite product of finite sets is finite -/
lemma Coprod_cofinite {δ : Type*} {κ : δ → Type*} [fintype δ] :
  filter.Coprod (λ d, (cofinite : filter (κ d))) = cofinite :=
begin
  ext S,
  rcases compl_surjective S with ⟨S, rfl⟩,
  simp_rw [compl_mem_Coprod_iff, mem_cofinite, compl_compl],
  split,
  { rintro ⟨t, htf, hsub⟩,
    exact (finite.pi htf).subset hsub },
  { exact λ hS, ⟨λ i, eval i '' S, λ i, hS.image _, subset_pi_eval_image _ _⟩ }
end

end filter

open filter

lemma set.finite.compl_mem_cofinite {s : set α} (hs : s.finite) : sᶜ ∈ (@cofinite α) :=
mem_cofinite.2 $ (compl_compl s).symm ▸ hs

lemma set.finite.eventually_cofinite_nmem {s : set α} (hs : s.finite) : ∀ᶠ x in cofinite, x ∉ s :=
hs.compl_mem_cofinite

lemma finset.eventually_cofinite_nmem (s : finset α) : ∀ᶠ x in cofinite, x ∉ s :=
s.finite_to_set.eventually_cofinite_nmem

lemma set.infinite_iff_frequently_cofinite {s : set α} :
  set.infinite s ↔ (∃ᶠ x in cofinite, x ∈ s) :=
frequently_cofinite_iff_infinite.symm

lemma filter.eventually_cofinite_ne (x : α) : ∀ᶠ a in cofinite, a ≠ x :=
(set.finite_singleton x).eventually_cofinite_nmem

lemma filter.le_cofinite_iff_compl_singleton_mem {l : filter α} :
  l ≤ cofinite ↔ ∀ x, {x}ᶜ ∈ l :=
begin
  refine ⟨λ h x, h (finite_singleton x).compl_mem_cofinite, λ h s (hs : sᶜ.finite), _⟩,
  rw [← compl_compl s, ← bUnion_of_singleton sᶜ, compl_Union₂,filter.bInter_mem hs],
  exact λ x _, h x
end

/-- If `α` is a sup-semilattice with no maximal element, then `at_top ≤ cofinite`. -/
lemma at_top_le_cofinite [semilattice_sup α] [no_max_order α] : (at_top : filter α) ≤ cofinite :=
begin
  refine compl_surjective.forall.2 (λ s hs, _),
  rcases eq_empty_or_nonempty s with rfl|hne, { simp only [compl_empty, univ_mem] },
  rw [mem_cofinite, compl_compl] at hs, lift s to finset α using hs,
  rcases exists_gt (s.sup' hne id) with ⟨y, hy⟩,
  filter_upwards [mem_at_top y] with x hx hxs,
  exact (finset.le_sup' id hxs).not_lt (hy.trans_le hx)
end

/-- For natural numbers the filters `cofinite` and `at_top` coincide. -/
lemma nat.cofinite_eq_at_top : @cofinite ℕ = at_top :=
begin
  refine le_antisymm _ at_top_le_cofinite,
  refine at_top_basis.ge_iff.2 (λ N hN, _),
  simpa only [mem_cofinite, compl_Ici] using finite_lt_nat N
end

lemma nat.frequently_at_top_iff_infinite {p : ℕ → Prop} :
  (∃ᶠ n in at_top, p n) ↔ set.infinite {n | p n} :=
by simp only [← nat.cofinite_eq_at_top, frequently_cofinite_iff_infinite]

lemma filter.tendsto.exists_within_forall_le {α β : Type*} [linear_order β] {s : set α}
  (hs : s.nonempty)
  {f : α → β} (hf : filter.tendsto f filter.cofinite filter.at_top) :
  ∃ a₀ ∈ s, ∀ a ∈ s, f a₀ ≤ f a :=
begin
  rcases em (∃ y ∈ s, ∃ x, f y < x) with ⟨y, hys, x, hx⟩|not_all_top,
  { -- the set of points `{y | f y < x}` is nonempty and finite, so we take `min` over this set
    have : finite {y | ¬x ≤ f y} := (filter.eventually_cofinite.mp (tendsto_at_top.1 hf x)),
    simp only [not_le] at this,
    obtain ⟨a₀, ⟨ha₀ : f a₀ < x, ha₀s⟩, others_bigger⟩ :=
      exists_min_image _ f (this.inter_of_left s) ⟨y, hx, hys⟩,
    refine ⟨a₀, ha₀s, λ a has, (lt_or_le (f a) x).elim _ (le_trans ha₀.le)⟩,
    exact λ h, others_bigger a ⟨h, has⟩ },
  { -- in this case, f is constant because all values are at top
    push_neg at not_all_top,
    obtain ⟨a₀, ha₀s⟩ := hs,
    exact ⟨a₀, ha₀s, λ a ha, not_all_top a ha (f a₀)⟩ }
end

lemma filter.tendsto.exists_forall_le {α β : Type*} [nonempty α] [linear_order β]
  {f : α → β} (hf : tendsto f cofinite at_top) :
  ∃ a₀, ∀ a, f a₀ ≤ f a :=
let ⟨a₀, _, ha₀⟩ := hf.exists_within_forall_le univ_nonempty in ⟨a₀, λ a, ha₀ a (mem_univ _)⟩

lemma filter.tendsto.exists_within_forall_ge {α β : Type*} [linear_order β] {s : set α}
  (hs : s.nonempty)
  {f : α → β} (hf : filter.tendsto f filter.cofinite filter.at_bot) :
  ∃ a₀ ∈ s, ∀ a ∈ s, f a ≤ f a₀ :=
@filter.tendsto.exists_within_forall_le _ (order_dual β) _ _ hs _ hf

lemma filter.tendsto.exists_forall_ge {α β : Type*} [nonempty α] [linear_order β]
  {f : α → β} (hf : tendsto f cofinite at_bot) :
  ∃ a₀, ∀ a, f a ≤ f a₀ :=
@filter.tendsto.exists_forall_le _ (order_dual β) _ _ _ hf

/-- For an injective function `f`, inverse images of finite sets are finite. -/
lemma function.injective.tendsto_cofinite {α β : Type*} {f : α → β} (hf : injective f) :
  tendsto f cofinite cofinite :=
λ s h, h.preimage (hf.inj_on _)

/-- An injective sequence `f : ℕ → ℕ` tends to infinity at infinity. -/
lemma function.injective.nat_tendsto_at_top {f : ℕ → ℕ} (hf : injective f) :
  tendsto f at_top at_top :=
nat.cofinite_eq_at_top ▸ hf.tendsto_cofinite


import .mylist
import .sorting

namespace hidden
namespace mylist

open mynat

universes u v
variables {T: Sort v} {T2: Sort u}
variables {T3: Type u} {T4: Type v}
variables {m n k: mynat}
variables {lst lst1 lst2: mylist T}
variables {lst' lst1' lst2': mylist T2}

-- classic map function
def map (f: T → T2): mylist T → mylist T2
| empty        := empty
| (x :: xs) := f x :: map xs

-- aka foldl
-- this form looks yuckier but I think it's nicer to prove things with
def reduce (f: T → T → T): Π lst: mylist T, lst ≠ empty → T
| empty h             := absurd rfl h
| (x :: empty) h      := x
| (x :: y :: xs) h := f x (reduce (y :: xs) cons_not_empty)

-- reduce with a "default" value for empty lists
def reduce_d (f: T → T → T) (default: T): mylist T → T
| empty := default
| (x :: xs) := f x (reduce_d xs)

def for_all (p: T → Prop) (lst: mylist T): Prop :=
reduce_d and true (map p lst)

def for_some (p: T → Prop) (lst: mylist T): Prop :=
reduce_d or false (map p lst)

def contains (x: T3) (lst: mylist T3): Prop :=
for_some (λ y, x = y) lst

instance: has_mem T3 (mylist T3) := ⟨contains⟩

def filter (p: T → Prop)
[hpdec: ∀ t: T, decidable (p t)]: mylist T → mylist T
| empty := empty
| (x :: xs) := if p x then x :: filter xs else filter xs

-- make n zeroes
def zeroes: mynat → mylist mynat
| 0        := empty
| (succ n) := 0 :: zeroes n

-- list 0, 1, 2, ..., n - 1
def list_zero_to: mynat → mylist mynat
| 0        := empty
| (succ n) := 0 :: map succ (list_zero_to n)

theorem for_all_iff_forall (p: T3 → Prop) (lst: mylist T3):
for_all p lst ↔ ∀ x: T3, contains x lst → p x :=
begin
  split, {
    assume hfa,
    induction lst with y ys ih_ys, {
      intro x,
      assume h,
      exfalso, from h,
    }, {
      intro x,
      assume h,
      cases h with h h, {
        rw h,
        from hfa.left,
      }, {
        apply ih_ys, {
          from hfa.right,
        }, {
          from h,
        },
      },
    },
  }, {
    assume hfa,
    induction lst with y ys ih_ys, {
      trivial,
    }, {
      split, {
        apply hfa,
        left,
        from rfl,
      }, {
        apply ih_ys,
        intro x,
        assume h,
        apply hfa,
        right,
        from h,
      },
    },
  },
end

theorem for_some_iff_exists (p: T3 → Prop) (lst: mylist T3):
for_some p lst ↔ ∃ x: T3, contains x lst ∧ p x :=
begin
  split, {
    assume hfs,
    induction lst with y ys ih_ys, {
      exfalso, from hfs,
    }, {
      cases hfs with hfs hfs, {
        existsi y,
        split, {
          left,
          from rfl,
        }, {
          assumption,
        },
      }, {
        cases ih_ys hfs with x hx,
        existsi x,
        split, {
          right,
          from hx.left,
        }, {
          from hx.right,
        },
      },
    },
  }, {
    assume hfs,
    induction lst with y ys ih_ys, {
      cases hfs with x hx,
      exfalso, from hx.left,
    }, {
      cases hfs with x hx,
      cases hx with hx hp,
      cases hx with hx hx, {
        left,
        rw ←hx,
        assumption,
      }, {
        right,
        apply ih_ys,
        existsi x,
        split; assumption,
      },
    },
  },
end

theorem len_zeroes: len (zeroes m) = m :=
begin
  induction m with m hm, {
    refl,
  }, {
    unfold zeroes,
    unfold len,
    rw hm,
  },
end

theorem get_a_zero
(hml: m < len (zeroes n)):
get m (zeroes n) hml = (0: mynat) :=
begin
  induction n with n hn generalizing m, {
    exfalso,
    from lt_nzero hml,
  }, {
    unfold zeroes,
    cases m, {
      refl,
    }, {
      unfold get,
      apply hn,
    },
  },
end

theorem len_map
(f: T → T2):
len (map f lst) = len lst :=
begin
  induction lst with head tail h_ih, {
    refl,
  }, {
    unfold map,
    unfold len,
    rw h_ih,
  },
end

theorem len_list_zero_to: len (list_zero_to m) = m :=
begin
  induction m with m hm, {
    refl,
  }, {
    unfold list_zero_to,
    unfold len,
    rw len_map,
    rw hm,
  },
end

theorem contains_map (f: T3 → T4) (x: T3) (lst: mylist T3):
contains x lst → contains (f x) (map f lst) :=
begin
  assume hxl,
  induction lst with y ys ih_ys, {
    exfalso, from hxl,
  }, {
    cases hxl with hxl hxl, {
      rw hxl,
      left,
      from rfl,
    }, {
      right,
      apply ih_ys,
      assumption,
    },
  },
end

-- should probably be shortened or at least split up
theorem contains_filter (x: T3) (lst: mylist T3)
(p: T3 → Prop)
[hpdec: ∀ t: T3, decidable (p t)]:
contains x (filter p lst) ↔ contains x lst ∧ p x :=
begin
  split; assume hx, {
    split, {
      induction lst with y ys ih_ys, {
        exfalso, from hx,
      }, {
        by_cases hpy: p y, {
          unfold filter at hx,
          rw if_pos hpy at hx,
          cases hx with hx hx, {
            rw hx,
            left,
            from rfl,
          }, {
            right,
            apply ih_ys,
            assumption,
          },
        }, {
          unfold filter at hx,
          rw if_neg hpy at hx,
          right,
          apply ih_ys,
          assumption,
        },
      },
    }, {
      induction lst with y ys ih_ys, {
        exfalso, from hx,
      }, {
        by_cases hpy: p y, {
          unfold filter at hx,
          rw if_pos hpy at hx,
          cases hx with hx hx, {
            rw hx,
            assumption,
          }, {
            apply ih_ys,
            assumption,
          },
        }, {
          unfold filter at hx,
          rw if_neg hpy at hx,
          apply ih_ys,
          assumption,
        },
      },
    },
  }, {
    induction lst with y ys ih_ys, {
      exfalso,
      from hx.left,
    }, {
      by_cases hpy: p y, {
        unfold filter,
        rw if_pos hpy,
        cases hx.left with hxys hxys, {
          rw hxys,
          left,
          from rfl,
        }, {
          right,
          apply ih_ys,
          split, {
            assumption,
          }, {
            from hx.right,
          },
        },
      }, {
        unfold filter,
        rw if_neg hpy,
        apply ih_ys,
        split, {
          cases hx.left with hxys hxys, {
            rw ←hxys at hpy,
            exfalso,
            from hpy hx.right,
          }, {
            assumption,
          },
        }, {
          from hx.right,
        },
      },
    },
  },
end

theorem get_map'
(f: T → T2)
(hml: m < len lst)
(hml': m < len (map f lst)):
get m (map f lst) hml' = f (get m lst hml) :=
begin
  induction lst with head tail h_ih generalizing m, {
    exfalso,
    from lt_nzero hml,
  }, {
    cases m, {
      refl,
    }, {
      unfold map,
      unfold get,
      apply h_ih,
    },
  },
end

-- more useful version for simplifying rewrites
theorem get_map
(f: T → T2)
(hml: m < len (map f lst)):
get m (map f lst) hml
  = f (get m lst begin rw len_map at hml, assumption, end)
:= get_map' _ _ _

theorem get_zero_to
(hnl: n < len (list_zero_to m)):
get n (list_zero_to m) hnl = n :=
begin
  induction m with m hm generalizing n, {
    exfalso,
    from lt_nzero hnl,
  }, {
    unfold list_zero_to,
    cases n, {
      refl,
    }, {
      unfold get,
      rw get_map,
      rw hm,
    },
  },
end

theorem map_concat (f: T → T2):
map f (lst1 ++ lst2) = map f lst1 ++ map f lst2 :=
begin
  induction lst1 with x xs ih_xs, {
    refl,
  }, {
    rw cons_concat,
    unfold map,
    rw ih_xs,
    refl,
  },
end

-- in anticipation of defining products of finite multisets

private lemma concat_nempty_left
{lst1 lst2: mylist T}
(h1: lst1 ≠ empty):
lst1 ++ lst2 ≠ empty :=
begin
  rw nonempty_iff_len_nonzero at *,
  rw nzero_iff_zero_lt at *,
  rw len_concat_add,
  from lt_add_rhs h1,
end

private lemma concat_nempty_right
{lst1 lst2: mylist T}
(h2: lst2 ≠ empty):
lst1 ++ lst2 ≠ empty :=
begin
  rw nonempty_iff_len_nonzero at *,
  rw nzero_iff_zero_lt at *,
  rw len_concat_add,
  rw add_comm,
  from lt_add_rhs h2,
end

theorem reduce_assoc_concat
(f: mynat → mynat → mynat)
(hassoc: is_associative _ f)
(lst1 lst2: mylist mynat)
(h1ne: lst1 ≠ empty) (h2ne: lst2 ≠ empty):
reduce f (lst1 ++ lst2) (concat_nempty_left h1ne) = f (reduce f lst1 h1ne) (reduce f lst2 h2ne) :=
begin
  induction lst1 with x xs hxs, {
    contradiction,
  }, {
    cases xs with x' xs, {
      dsimp,
      unfold reduce,
      cases lst2 with y ys, {
        contradiction,
      }, {
        refl,
      },
    }, {
      unfold reduce,
      conv {
        to_lhs,
        congr, skip,
        rw cons_concat,
        rw cons_concat,
      },
      unfold reduce,
      have := hxs cons_not_empty,
      conv at this {
        to_lhs,
        congr, skip,
        rw cons_concat,
      },
      rw this,
      symmetry,
      apply hassoc.assoc,
    },
  },
end

theorem reduce_comm_assoc_concat_comm
(f: mynat → mynat → mynat)
(hcomm: is_commutative _ f)
(hassoc: is_associative _ f)
(lst1 lst2: mylist mynat)
(h1ne: lst1 ≠ empty):
reduce f (lst1 ++ lst2) (concat_nempty_left h1ne) = reduce f (lst2 ++ lst1) (concat_nempty_right h1ne) :=
begin
  cases lst1 with x xs, {
    contradiction,
  }, {
    cases lst2 with y ys, {
      simp,
    }, {
      rw reduce_assoc_concat f hassoc (x :: xs) (y :: ys) cons_not_empty cons_not_empty,
      rw reduce_assoc_concat f hassoc (y :: ys) (x :: xs) cons_not_empty cons_not_empty,
      apply hcomm.comm,
    },
  },
end

theorem reduce_comm_assoc_concat_transpose
(f: mynat → mynat → mynat)
(hcomm: is_commutative _ f)
(hassoc: is_associative _ f)
(lst1 lst2 lst3: mylist mynat)
(h1ne: lst1 ≠ empty):
reduce f (lst1 ++ lst2 ++ lst3) (concat_nempty_left (concat_nempty_left h1ne)) = reduce f (lst2 ++ lst1 ++ lst3) (concat_nempty_left (concat_nempty_right h1ne)) :=
begin
  cases lst3 with z zs, {
    conv {
      congr,
      congr, skip,
      rw concat_empty,
      skip, congr, skip,
      rw concat_empty,
    },
    apply reduce_comm_assoc_concat_comm _ hcomm hassoc,
    from h1ne,
  }, {
    rw reduce_assoc_concat f hassoc (lst1 ++ lst2) (z :: zs) _ cons_not_empty,
    rw reduce_assoc_concat f hassoc (lst2 ++ lst1) (z :: zs) _ cons_not_empty,
    rw reduce_comm_assoc_concat_comm f hcomm hassoc lst1 lst2 h1ne,
  },
end

private lemma reduce_comm_assoc_concat_interchange
(f: mynat → mynat → mynat)
(hcomm: is_commutative _ f)
(hassoc: is_associative _ f)
(a b c d e: mylist mynat)
(hb: b ≠ empty) (hd: d ≠ empty):
reduce f (a ++ b ++ c ++ d ++ e) (concat_nempty_left (concat_nempty_right hd)) = reduce f (a ++ d ++ c ++ b ++ e) (concat_nempty_left (concat_nempty_right hb)) :=
begin
  -- tragically we aren't allowed to clear these hypotheses
  have h1: (a ++ b ++ c ++ d ++ e) = (a ++ b) ++ (c ++ d) ++ e, {
    -- also known as a_refl
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h1},
  rw reduce_comm_assoc_concat_transpose f hcomm hassoc,
  have h2: (c ++ d ++ (a ++ b) ++ e) = (c ++ d ++ a) ++ (b ++ e), {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h2},
  rw reduce_comm_assoc_concat_comm f hcomm hassoc,
  have h3: (b ++ e ++ (c ++ d ++ a)) = (b ++ e ++ c) ++ d ++ a, {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h3},
  rw reduce_comm_assoc_concat_transpose f hcomm hassoc,
  have h4: (d ++ (b ++ e ++ c) ++ a) = (d ++ b ++ e ++ c) ++ a, {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h4},
  rw reduce_comm_assoc_concat_comm f hcomm hassoc,
  have h5: (a ++ (d ++ b ++ e ++ c)) = (a ++ d) ++ b ++ (e ++ c), {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h5},
  rw reduce_comm_assoc_concat_transpose f hcomm hassoc,
  have h6: (b ++ (a ++ d) ++ (e ++ c)) = (b ++ a ++ d ++ e) ++ c, {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h6},
  rw reduce_comm_assoc_concat_comm f hcomm hassoc,
  have h7: (c ++ (b ++ a ++ d ++ e)) = (c ++ b) ++ (a ++ d) ++ e, {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h7},
  rw reduce_comm_assoc_concat_transpose f hcomm hassoc,
  conv {congr, congr, skip},
  have h8: a ++ d ++ (c ++ b) ++ e = a ++ d ++ c ++ b ++ e, {
    repeat {rw ←concat_assoc},
  },
  conv {congr, congr, skip, rw h8},
  -- these are all concatenations involving a non-empty list
  from concat_nempty_right hb,
  from concat_nempty_left (concat_nempty_right hd),
  from concat_nempty_right hd,
  repeat {rw concat_assoc},
  from concat_nempty_left hd,
  from concat_nempty_left hb,
  from concat_nempty_right (concat_nempty_left hd),
  from concat_nempty_right hb,
end

theorem reduce_comm_assoc_swap
(f: mynat → mynat → mynat)
(hcomm: is_commutative _ f)
(hassoc: is_associative _ f)
(lst: mylist mynat)
(hmn: m < n)
(hnl: n < len lst):
reduce f lst (
  begin
    rw nonempty_iff_len_nonzero,
    rw nzero_iff_zero_lt,
    from le_lt_chain n zero_le hnl,
  end
) = reduce f (swap_elems m n lst hmn hnl) (
  begin
    rw nonempty_iff_len_nonzero,
    rw len_swap,
    rw nzero_iff_zero_lt,
    from le_lt_chain n zero_le hnl,
  end
) :=
begin
  unfold swap_elems,
  rw reduce_comm_assoc_concat_interchange f hcomm hassoc,
  congr,
  have := take_concat_drop (lt_impl_le (mynat.lt_trans hmn hnl)),
  conv in lst {rw ←this}, clear this,
  repeat {rw concat_assoc},
  congr,
  have := @cons_head_tail _ (drop m lst (lt_impl_le (mynat.lt_trans hmn hnl))) _,
  rw ←this, clear this,
  rw ←@get_head_drop _ lst m,
  rw singleton_concat_cons,
  congr,
  have := @drop_one_tail _ (drop m lst (lt_impl_le (mynat.lt_trans hmn hnl))) _,
  rw ←this, clear this,
  rw drop_drop,
  unfold slice,
  have := @take_concat_drop _ (drop m.succ lst _) (n - m.succ) _,
  conv {
    to_lhs,
    congr,
    rw add_one_succ,
  },
  conv {
    to_lhs,
    rw ←this,
  }, clear this,
  congr,
  rw drop_drop,
  have := sub_add_condition.mpr (lt_iff_succ_le.mp hmn),
  rw add_comm at this,
  conv {
    to_lhs,
    congr,
    rw this,
  },
  have := @cons_head_tail _ (drop n lst (lt_impl_le hnl)) _,
  rw ←this, clear this,
  rw ←@get_head_drop _ lst n,
  rw singleton_concat_cons,
  congr,
  rw ←@drop_one_tail _ (drop n lst _),
  rw drop_drop,
  refl,

  apply @le_cancel _ _ n,
  rw len_drop,
  rw add_comm,
  from lt_iff_succ_le.mp hnl,

  apply @le_cancel _ _ m,
  rw len_drop,
  rw add_comm,
  from lt_iff_succ_le.mp (lt_trans hmn hnl),

  from cons_not_empty,
  from cons_not_empty,
end

-- takes some of the casework out
theorem reduce_congr
(f: mynat → mynat → mynat)
(x: mynat) (xs ys: mylist mynat)
(hxs: xs ≠ empty) (hys: ys ≠ empty):
reduce f xs hxs = reduce f ys hys
→ reduce f (x :: xs) cons_not_empty = reduce f (x :: ys) cons_not_empty :=
begin
  assume h,
  cases xs with x' xs, {
    contradiction,
  }, {
    cases ys with y' ys, {
      contradiction,
    }, {
      unfold reduce,
      congr,
      assumption,
    },
  },
end

-- TODO: for general types with decidable_eq
theorem reduce_comm_assoc_perm
(f: mynat → mynat → mynat)
(hcomm: is_commutative _ f)
(hassoc: is_associative _ f)
(lst1 lst2: mylist mynat)
(h1ne: lst1 ≠ empty) (h2ne: lst2 ≠ empty)
(hperm: is_perm lst1 lst2):
reduce f lst1 h1ne = reduce f lst2 h2ne :=
begin
  induction hl: len lst1 with n hn generalizing lst1 lst2, {
    have := empty_iff_len_zero.mpr hl,
    contradiction,
  }, {
    have hl1l2 := perm_len hperm,
    cases lst1 with x xs, {
      contradiction,
    }, {
      cases lst2 with y ys, {
        contradiction,
      }, {
        have hidxy: count y (x :: xs) ≠ 0, {
          rw hperm y,
          unfold count,
          rw if_pos rfl,
          from succ_ne_zero,
        },
        by_cases hxy: x = y, {
          conv {congr, congr, skip, rw hxy},
          cases xs with x' xs, {
            cases ys with y' ys, {
              refl,
            }, {
              cases hl1l2,
            },
          },
          cases ys with y' ys, {
            cases hl1l2,
          }, {
            apply reduce_congr f y (x' :: xs) (y' :: ys) cons_not_empty cons_not_empty,
            apply hn,
            rw hxy at hperm,
            from perm_head_cancel hperm,
            from succ_inj hl,
          },
        }, {
          have h0lidxy: 0 < index y (x :: xs) hidxy, {
            assume h,
            have hidxy0 := le_zero_iff.mp h,
            have := get_index hidxy (index_valid _),
            conv at this {
              congr,
              congr,
              rw hidxy0,
            },
            dsimp at this,
            contradiction,
          },
          have hswapne: swap_elems 0 (index y (x :: xs) hidxy) (x :: xs) h0lidxy (index_valid _) ≠ mylist.empty, {
            rw nonempty_iff_len_nonzero,
            rw len_swap,
            from succ_ne_zero,
          },
          transitivity reduce f (swap_elems 0 (index y (x :: xs) hidxy) (x :: xs) h0lidxy (index_valid _)) hswapne, {
            apply reduce_comm_assoc_swap,
            from hcomm,
            from hassoc,
          }, {
            unfold swap_elems,
            dsimp,
            conv {
              to_lhs,
              congr, skip, congr,
              rw get_index,
            },
            cases ys with y' ys, {
              have: count y (x :: xs) = 0, {
                unfold count,
                rw if_neg (λ h, hxy (eq.symm h)),
                rw empty_iff_len_zero.mpr (succ_inj hl1l2),
                refl,
              },
              contradiction,
            }, {
              apply reduce_congr f y _ (y' :: ys) _ cons_not_empty,
              apply hn,
              apply @perm_head_cancel y,
              apply @perm_trans _ (x :: xs) _,
              have := @swap_perm 0 (index y (x :: xs) hidxy) (x :: xs) _ _,
              unfold swap_elems at this,
              dsimp at this,
              rw get_index at this,
              from perm_symm this,
              assumption,

              suffices: len (swap_elems 0 (index y (x :: xs) hidxy) (x :: xs) _ _) = n.succ,
              unfold swap_elems at this,
              dsimp at this,
              repeat {rw len_concat_add at this},
              simp at this,
              simp,
              assumption,

              have := @swap_perm 0 (index y (x :: xs) hidxy) (x :: xs) _ _,
              rw ←hl,
              apply perm_len,
              apply perm_symm,
              assumption,

              rw nonempty_iff_len_nonzero,
              rw nzero_iff_zero_lt,
              rw len_concat_add,
              rw len_concat_add,
              rw add_comm,
              from zero_lt_succ,
            }
          },
        },
      },
    },
  },
end

end mylist
end hidden


/-
Copyright (c) 2022 David Kurniadi Angdinata. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Kurniadi Angdinata
-/

import ring_theory.dedekind_domain.adic_valuation

/-!
# `S`-integers and `S`-units of fraction fields of Dedekind domains

Let `K` be the field of fractions of a Dedekind domain `R`, and let `S` be a set of prime ideals in
the height one spectrum of `R`. An `S`-integer of `K` is defined to have `v`-adic valuation at most
one for all primes ideals `v` away from `S`, whereas an `S`-unit of `Kˣ` is defined to have `v`-adic
valuation exactly one for all prime ideals `v` away from `S`.

This file defines the subalgebra of `S`-integers of `K` and the subgroup of `S`-units of `Kˣ`, where
`K` can be specialised to the case of a number field or a function field separately.

## Main definitions

 * `set.integer`: `S`-integers.
 * `set.unit`: `S`-units.
 * TODO: localised notation for `S`-integers.

## Main statements

 * `set.unit_equiv_units_integer`: `S`-units are units of `S`-integers.
 * TODO: proof that `S`-units is the kernel of a map to a product.
 * TODO: proof that `∅`-integers is the usual ring of integers.
 * TODO: finite generation of `S`-units and Dirichlet's `S`-unit theorem.

## References

 * [D Marcus, *Number Fields*][marcus1977number]
 * [J W S Cassels, A Frölich, *Algebraic Number Theory*][cassels1967algebraic]
 * [J Neukirch, *Algebraic Number Theory*][Neukirch1992]

## Tags

S integer, S-integer, S unit, S-unit
-/

namespace set

noncomputable theory

open is_dedekind_domain

open_locale non_zero_divisors

universes u v

variables {R : Type u} [comm_ring R] [is_domain R] [is_dedekind_domain R]
  (S : set $ height_one_spectrum R) (K : Type v) [field K] [algebra R K] [is_fraction_ring R K]

/-! ## `S`-integers -/

/-- The `R`-subalgebra of `S`-integers of `K`. -/
@[simps] def integer : subalgebra R K :=
{ algebra_map_mem' := λ x v _, v.valuation_le_one x,
  .. (⨅ v ∉ S, (v : height_one_spectrum R).valuation.valuation_subring.to_subring).copy
      {x : K | ∀ v ∉ S, (v : height_one_spectrum R).valuation x ≤ 1} $ set.ext $ λ _,
      by simpa only [set_like.mem_coe, subring.mem_infi] }

lemma integer_eq :
  (S.integer K).to_subring
    = ⨅ v ∉ S, (v : height_one_spectrum R).valuation.valuation_subring.to_subring :=
set_like.ext' $ by simpa only [integer, subring.copy_eq]

lemma integer_valuation_le_one (x : S.integer K) {v : height_one_spectrum R} (hv : v ∉ S) :
  v.valuation (x : K) ≤ 1 :=
x.property v hv

/-! ## `S`-units -/

/-- The subgroup of `S`-units of `Kˣ`. -/
@[simps] def unit : subgroup Kˣ :=
(⨅ v ∉ S, (v : height_one_spectrum R).valuation.valuation_subring.unit_group).copy
  {x : Kˣ | ∀ v ∉ S, (v : height_one_spectrum R).valuation (x : K) = 1} $ set.ext $ λ _,
  by simpa only [set_like.mem_coe, subgroup.mem_infi, valuation.mem_unit_group_iff]

lemma unit_eq :
  S.unit K = ⨅ v ∉ S, (v : height_one_spectrum R).valuation.valuation_subring.unit_group :=
subgroup.copy_eq _ _ _

lemma unit_valuation_eq_one (x : S.unit K) {v : height_one_spectrum R} (hv : v ∉ S) :
  v.valuation (x : K) = 1 :=
x.property v hv

/-- The group of `S`-units is the group of units of the ring of `S`-integers. -/
@[simps] def unit_equiv_units_integer : S.unit K ≃* (S.integer K)ˣ :=
{ to_fun    := λ x, ⟨⟨x, λ v hv, (x.property v hv).le⟩, ⟨↑x⁻¹, λ v hv, ((x⁻¹).property v hv).le⟩,
    subtype.ext x.val.val_inv, subtype.ext x.val.inv_val⟩,
  inv_fun   := λ x, ⟨units.mk0 x $ λ hx, x.ne_zero ((subring.coe_eq_zero_iff _).mp hx),
    λ v hv, eq_one_of_one_le_mul_left (x.val.property v hv) (x.inv.property v hv) $ eq.ge $
      by { rw [← map_mul], convert v.valuation.map_one, exact subtype.mk_eq_mk.mp x.val_inv }⟩,
  left_inv  := λ _, by { ext, refl },
  right_inv := λ _, by { ext, refl },
  map_mul'  := λ _ _, by { ext, refl } }

end set