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

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

/-!
# Ideals in product rings

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

For commutative rings `R` and `S` and ideals `I ≤ R`, `J ≤ S`, we define `ideal.prod I J` as the
product `I × J`, viewed as an ideal of `R × S`. In `ideal_prod_eq` we show that every ideal of
`R × S` is of this form.  Furthermore, we show that every prime ideal of `R × S` is of the form
`p × S` or `R × p`, where `p` is a prime ideal.
-/

universe u v

variable {R : Type u} {S : Type v} [Ring R] [Ring S] (I I' : Ideal R) (J J' : Ideal S)

namespace Ideal

/- warning: ideal.prod -> Ideal.prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S], (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) -> (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) -> (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S], (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) -> (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) -> (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))
Case conversion may be inaccurate. Consider using '#align ideal.prod Ideal.prodₓ'. -/
/-- `I × J` as an ideal of `R × S`. -/
def prod : Ideal (R × S) where
  carrier := { x | x.fst ∈ I ∧ x.snd ∈ J }
  zero_mem' := by simp
  add_mem' := by
    rintro ⟨a₁, a₂⟩ ⟨b₁, b₂⟩ ⟨ha₁, ha₂⟩ ⟨hb₁, hb₂⟩
    exact ⟨I.add_mem ha₁ hb₁, J.add_mem ha₂ hb₂⟩
  smul_mem' := by
    rintro ⟨a₁, a₂⟩ ⟨b₁, b₂⟩ ⟨hb₁, hb₂⟩
    exact ⟨I.mul_mem_left _ hb₁, J.mul_mem_left _ hb₂⟩
#align ideal.prod Ideal.prod

#print Ideal.mem_prod /-
@[simp]
theorem mem_prod {r : R} {s : S} : (⟨r, s⟩ : R × S) ∈ prod I J ↔ r ∈ I ∧ s ∈ J :=
  Iff.rfl
#align ideal.mem_prod Ideal.mem_prod
-/

/- warning: ideal.prod_top_top -> Ideal.prod_top_top is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S], Eq.{succ (max u1 u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.hasTop.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.hasTop.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Top.top.{max u1 u2} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Submodule.hasTop.{max u1 u2, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u2} (Prod.{u1, u2} R S) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u2} (Prod.{u1, u2} R S) (Semiring.toNonAssocSemiring.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))))) (Semiring.toModule.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S], Eq.{max (succ u1) (succ u2)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.instTopSubmodule.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.instTopSubmodule.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Top.top.{max u1 u2} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Submodule.instTopSubmodule.{max u1 u2, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u1} (Prod.{u1, u2} R S) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u1} (Prod.{u1, u2} R S) (Semiring.toNonAssocSemiring.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))))) (Semiring.toModule.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))))
Case conversion may be inaccurate. Consider using '#align ideal.prod_top_top Ideal.prod_top_topₓ'. -/
@[simp]
theorem prod_top_top : prod (⊤ : Ideal R) (⊤ : Ideal S) = ⊤ :=
  Ideal.ext <| by simp
#align ideal.prod_top_top Ideal.prod_top_top

/- warning: ideal.ideal_prod_eq -> Ideal.ideal_prod_eq is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))), Eq.{succ (max u1 u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) I (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Ideal.map.{max u1 u2, u1, max u1 u2} (Prod.{u1, u2} R S) R (RingHom.{max u1 u2, u1} (Prod.{u1, u2} R S) R (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u1} R _inst_1) (RingHom.ringHomClass.{max u1 u2, u1} (Prod.{u1, u2} R S) R (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (RingHom.fst.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) I) (Ideal.map.{max u1 u2, u2, max u1 u2} (Prod.{u1, u2} R S) S (RingHom.{max u1 u2, u2} (Prod.{u1, u2} R S) S (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u2} S _inst_2) (RingHom.ringHomClass.{max u1 u2, u2} (Prod.{u1, u2} R S) S (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (RingHom.snd.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) I))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))), Eq.{max (succ u1) (succ u2)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) I (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Ideal.map.{max u1 u2, u1, max u1 u2} (Prod.{u1, u2} R S) R (RingHom.{max u2 u1, u1} (Prod.{u1, u2} R S) R (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u1} R _inst_1) (RingHom.instRingHomClassRingHom.{max u1 u2, u1} (Prod.{u1, u2} R S) R (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (RingHom.fst.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) I) (Ideal.map.{max u1 u2, u2, max u1 u2} (Prod.{u1, u2} R S) S (RingHom.{max u2 u1, u2} (Prod.{u1, u2} R S) S (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u2} S _inst_2) (RingHom.instRingHomClassRingHom.{max u1 u2, u2} (Prod.{u1, u2} R S) S (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (RingHom.snd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) I))
Case conversion may be inaccurate. Consider using '#align ideal.ideal_prod_eq Ideal.ideal_prod_eqₓ'. -/
/-- Every ideal of the product ring is of the form `I × J`, where `I` and `J` can be explicitly
    given as the image under the projection maps. -/
theorem ideal_prod_eq (I : Ideal (R × S)) :
    I = Ideal.prod (map (RingHom.fst R S) I) (map (RingHom.snd R S) I) :=
  by
  apply Ideal.ext
  rintro ⟨r, s⟩
  rw [mem_prod, mem_map_iff_of_surjective (RingHom.fst R S) Prod.fst_surjective,
    mem_map_iff_of_surjective (RingHom.snd R S) Prod.snd_surjective]
  refine' ⟨fun h => ⟨⟨_, ⟨h, rfl⟩⟩, ⟨_, ⟨h, rfl⟩⟩⟩, _⟩
  rintro ⟨⟨⟨r, s'⟩, ⟨h₁, rfl⟩⟩, ⟨⟨r', s⟩, ⟨h₂, rfl⟩⟩⟩
  simpa using I.add_mem (I.mul_mem_left (1, 0) h₁) (I.mul_mem_left (0, 1) h₂)
#align ideal.ideal_prod_eq Ideal.ideal_prod_eq

/- warning: ideal.map_fst_prod -> Ideal.map_fst_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.map.{max u1 u2, u1, max u1 u2} (Prod.{u1, u2} R S) R (RingHom.{max u1 u2, u1} (Prod.{u1, u2} R S) R (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u1} R _inst_1) (RingHom.ringHomClass.{max u1 u2, u1} (Prod.{u1, u2} R S) R (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (RingHom.fst.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) I
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.map.{max u2 u1, u1, max u1 u2} (Prod.{u1, u2} R S) R (RingHom.{max u2 u1, u1} (Prod.{u1, u2} R S) R (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u1} R _inst_1) (RingHom.instRingHomClassRingHom.{max u1 u2, u1} (Prod.{u1, u2} R S) R (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (RingHom.fst.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) I
Case conversion may be inaccurate. Consider using '#align ideal.map_fst_prod Ideal.map_fst_prodₓ'. -/
@[simp]
theorem map_fst_prod (I : Ideal R) (J : Ideal S) : map (RingHom.fst R S) (prod I J) = I :=
  by
  ext
  rw [mem_map_iff_of_surjective (RingHom.fst R S) Prod.fst_surjective]
  exact
    ⟨by
      rintro ⟨x, ⟨h, rfl⟩⟩
      exact h.1, fun h => ⟨⟨x, 0⟩, ⟨⟨h, Ideal.zero_mem _⟩, rfl⟩⟩⟩
#align ideal.map_fst_prod Ideal.map_fst_prod

/- warning: ideal.map_snd_prod -> Ideal.map_snd_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Ideal.map.{max u1 u2, u2, max u1 u2} (Prod.{u1, u2} R S) S (RingHom.{max u1 u2, u2} (Prod.{u1, u2} R S) S (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u2} S _inst_2) (RingHom.ringHomClass.{max u1 u2, u2} (Prod.{u1, u2} R S) S (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (RingHom.snd.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) J
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Ideal.map.{max u2 u1, u2, max u1 u2} (Prod.{u1, u2} R S) S (RingHom.{max u2 u1, u2} (Prod.{u1, u2} R S) S (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ring.toSemiring.{u2} S _inst_2) (RingHom.instRingHomClassRingHom.{max u1 u2, u2} (Prod.{u1, u2} R S) S (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (RingHom.snd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) J
Case conversion may be inaccurate. Consider using '#align ideal.map_snd_prod Ideal.map_snd_prodₓ'. -/
@[simp]
theorem map_snd_prod (I : Ideal R) (J : Ideal S) : map (RingHom.snd R S) (prod I J) = J :=
  by
  ext
  rw [mem_map_iff_of_surjective (RingHom.snd R S) Prod.snd_surjective]
  exact
    ⟨by
      rintro ⟨x, ⟨h, rfl⟩⟩
      exact h.2, fun h => ⟨⟨0, x⟩, ⟨⟨Ideal.zero_mem _, h⟩, rfl⟩⟩⟩
#align ideal.map_snd_prod Ideal.map_snd_prod

/- warning: ideal.map_prod_comm_prod -> Ideal.map_prodComm_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{succ (max u2 u1)} (Ideal.{max u2 u1} (Prod.{u2, u1} S R) (Prod.semiring.{u2, u1} S R (Ring.toSemiring.{u2} S _inst_2) (Ring.toSemiring.{u1} R _inst_1))) (Ideal.map.{max u1 u2, max u2 u1, max (max u1 u2) u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (RingHom.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Prod.semiring.{u2, u1} S R (Ring.toSemiring.{u2} S _inst_2) (Ring.toSemiring.{u1} R _inst_1)) (RingHom.ringHomClass.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))) ((fun (a : Sort.{max (succ (max u1 u2)) (succ (max u2 u1))}) (b : Sort.{max (succ (max u1 u2)) (succ (max u2 u1))}) [self : HasLiftT.{max (succ (max u1 u2)) (succ (max u2 u1)), max (succ (max u1 u2)) (succ (max u2 u1))} a b] => self.0) (RingEquiv.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.hasMul.{u1, u2} R S (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasAdd.{u1, u2} R S (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasMul.{u2, u1} S R (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) (Prod.hasAdd.{u2, u1} S R (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))) (RingHom.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))) (HasLiftT.mk.{max (succ (max u1 u2)) (succ (max u2 u1)), max (succ (max u1 u2)) (succ (max u2 u1))} (RingEquiv.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.hasMul.{u1, u2} R S (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasAdd.{u1, u2} R S (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasMul.{u2, u1} S R (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) (Prod.hasAdd.{u2, u1} S R (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))) (RingHom.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))) (CoeTCₓ.coe.{max (succ (max u1 u2)) (succ (max u2 u1)), max (succ (max u1 u2)) (succ (max u2 u1))} (RingEquiv.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.hasMul.{u1, u2} R S (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasAdd.{u1, u2} R S (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasMul.{u2, u1} S R (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) (Prod.hasAdd.{u2, u1} S R (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))) (RingHom.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))) (RingHom.hasCoeT.{max (max u1 u2) u2 u1, max u1 u2, max u2 u1} (RingEquiv.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.hasMul.{u1, u2} R S (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasAdd.{u1, u2} R S (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasMul.{u2, u1} S R (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) (Prod.hasAdd.{u2, u1} S R (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))) (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (RingEquivClass.toRingHomClass.{max (max u1 u2) u2 u1, max u1 u2, max u2 u1} (RingEquiv.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.hasMul.{u1, u2} R S (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasAdd.{u1, u2} R S (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasMul.{u2, u1} S R (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) (Prod.hasAdd.{u2, u1} S R (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))) (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.nonAssocSemiring.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))) (Prod.nonAssocSemiring.{u2, u1} S R (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)) (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))) (RingEquiv.ringEquivClass.{max u1 u2, max u2 u1} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.hasMul.{u1, u2} R S (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasAdd.{u1, u2} R S (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))))) (Prod.hasMul.{u2, u1} S R (Distrib.toHasMul.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)))))) (Prod.hasAdd.{u2, u1} S R (Distrib.toHasAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2))))) (Distrib.toHasAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))))))) (RingEquiv.prodComm.{u1, u2} R S (NonAssocRing.toNonAssocSemiring.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1)) (NonAssocRing.toNonAssocSemiring.{u2} S (Ring.toNonAssocRing.{u2} S _inst_2)))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) (Ideal.prod.{u2, u1} S R _inst_2 _inst_1 J I)
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{max (succ u1) (succ u2)} (Ideal.{max u1 u2} (Prod.{u2, u1} S R) (Prod.instSemiringProd.{u2, u1} S R (Ring.toSemiring.{u2} S _inst_2) (Ring.toSemiring.{u1} R _inst_1))) (Ideal.map.{max u2 u1, max u1 u2, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (RingHom.{max u1 u2, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Prod.instNonAssocSemiringProd.{u2, u1} S R (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Prod.instSemiringProd.{u2, u1} S R (Ring.toSemiring.{u2} S _inst_2) (Ring.toSemiring.{u1} R _inst_1)) (RingHom.instRingHomClassRingHom.{max u1 u2, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Prod.instNonAssocSemiringProd.{u2, u1} S R (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (RingHomClass.toRingHom.{max u1 u2, max u1 u2, max u1 u2} (RingEquiv.{max u2 u1, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instMulProd.{u1, u2} R S (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Prod.instMulProd.{u2, u1} S R (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Prod.instAddSum.{u1, u2} R S (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Distrib.toAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))) (Prod.instAddSum.{u2, u1} S R (Distrib.toAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))))) (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Prod.instNonAssocSemiringProd.{u2, u1} S R (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (RingEquivClass.toRingHomClass.{max u1 u2, max u1 u2, max u1 u2} (RingEquiv.{max u2 u1, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instMulProd.{u1, u2} R S (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Prod.instMulProd.{u2, u1} S R (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Prod.instAddSum.{u1, u2} R S (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Distrib.toAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))) (Prod.instAddSum.{u2, u1} S R (Distrib.toAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))))) (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instNonAssocSemiringProd.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Prod.instNonAssocSemiringProd.{u2, u1} S R (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (RingEquiv.instRingEquivClassRingEquiv.{max u1 u2, max u1 u2} (Prod.{u1, u2} R S) (Prod.{u2, u1} S R) (Prod.instMulProd.{u1, u2} R S (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Prod.instMulProd.{u2, u1} S R (NonUnitalNonAssocSemiring.toMul.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Prod.instAddSum.{u1, u2} R S (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Distrib.toAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))) (Prod.instAddSum.{u2, u1} S R (Distrib.toAdd.{u2} S (NonUnitalNonAssocSemiring.toDistrib.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2))))) (Distrib.toAdd.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))))))) (RingEquiv.prodComm.{u1, u2} R S (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) (Ideal.prod.{u2, u1} S R _inst_2 _inst_1 J I)
Case conversion may be inaccurate. Consider using '#align ideal.map_prod_comm_prod Ideal.map_prodComm_prodₓ'. -/
@[simp]
theorem map_prodComm_prod :
    map ((RingEquiv.prodComm : R × S ≃+* S × R) : R × S →+* S × R) (prod I J) = prod J I :=
  by
  refine' trans (ideal_prod_eq _) _
  simp [map_map]
#align ideal.map_prod_comm_prod Ideal.map_prodComm_prod

/- warning: ideal.ideal_prod_equiv -> Ideal.idealProdEquiv is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S], Equiv.{succ (max u1 u2), max (succ u1) (succ u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S], Equiv.{succ (max u2 u1), max (succ u2) (succ u1)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)))
Case conversion may be inaccurate. Consider using '#align ideal.ideal_prod_equiv Ideal.idealProdEquivₓ'. -/
/-- Ideals of `R × S` are in one-to-one correspondence with pairs of ideals of `R` and ideals of
    `S`. -/
def idealProdEquiv : Ideal (R × S) ≃ Ideal R × Ideal S
    where
  toFun I := ⟨map (RingHom.fst R S) I, map (RingHom.snd R S) I⟩
  invFun I := prod I.1 I.2
  left_inv I := (ideal_prod_eq I).symm
  right_inv := fun ⟨I, J⟩ => by simp
#align ideal.ideal_prod_equiv Ideal.idealProdEquiv

/- warning: ideal.ideal_prod_equiv_symm_apply -> Ideal.idealProdEquiv_symm_apply is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{succ (max u1 u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (coeFn.{max 1 (max (max (succ u1) (succ u2)) (succ (max u1 u2))) (succ (max u1 u2)) (succ u1) (succ u2), max (max (succ u1) (succ u2)) (succ (max u1 u2))} (Equiv.{max (succ u1) (succ u2), succ (max u1 u2)} (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))) (fun (_x : Equiv.{max (succ u1) (succ u2), succ (max u1 u2)} (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))) => (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) -> (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))) (Equiv.hasCoeToFun.{max (succ u1) (succ u2), succ (max u1 u2)} (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))) (Equiv.symm.{succ (max u1 u2), max (succ u1) (succ u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.idealProdEquiv.{u1, u2} R S _inst_1 _inst_2)) (Prod.mk.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) I J)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)), Eq.{max (succ u1) (succ u2)} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) => Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Prod.mk.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) I J)) (FunLike.coe.{max (succ u2) (succ u1), max (succ u2) (succ u1), max (succ u2) (succ u1)} (Equiv.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))) (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (fun (_x : Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) => Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) _x) (Equiv.instFunLikeEquiv.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)))) (Equiv.symm.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Prod.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2))) (Ideal.idealProdEquiv.{u1, u2} R S _inst_1 _inst_2)) (Prod.mk.{u1, u2} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) I J)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)
Case conversion may be inaccurate. Consider using '#align ideal.ideal_prod_equiv_symm_apply Ideal.idealProdEquiv_symm_applyₓ'. -/
@[simp]
theorem idealProdEquiv_symm_apply (I : Ideal R) (J : Ideal S) :
    idealProdEquiv.symm ⟨I, J⟩ = prod I J :=
  rfl
#align ideal.ideal_prod_equiv_symm_apply Ideal.idealProdEquiv_symm_apply

/- warning: ideal.prod.ext_iff -> Ideal.prod.ext_iff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} {I' : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} {J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)} {J' : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)}, Iff (Eq.{succ (max u1 u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I' J')) (And (Eq.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) I I') (Eq.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) J J'))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} {I' : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} {J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)} {J' : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)}, Iff (Eq.{max (succ u1) (succ u2)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I' J')) (And (Eq.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) I I') (Eq.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) J J'))
Case conversion may be inaccurate. Consider using '#align ideal.prod.ext_iff Ideal.prod.ext_iffₓ'. -/
theorem prod.ext_iff {I I' : Ideal R} {J J' : Ideal S} : prod I J = prod I' J' ↔ I = I' ∧ J = J' :=
  by
  simp only [← ideal_prod_equiv_symm_apply, ideal_prod_equiv.symm.injective.eq_iff, Prod.mk.inj_iff]
#align ideal.prod.ext_iff Ideal.prod.ext_iff

/- warning: ideal.is_prime_of_is_prime_prod_top -> Ideal.isPrime_of_isPrime_prod_top is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)}, (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.hasTop.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))) -> (Ideal.IsPrime.{u1} R (Ring.toSemiring.{u1} R _inst_1) I)
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)}, (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.instTopSubmodule.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))) -> (Ideal.IsPrime.{u1} R (Ring.toSemiring.{u1} R _inst_1) I)
Case conversion may be inaccurate. Consider using '#align ideal.is_prime_of_is_prime_prod_top Ideal.isPrime_of_isPrime_prod_topₓ'. -/
theorem isPrime_of_isPrime_prod_top {I : Ideal R} (h : (Ideal.prod I (⊤ : Ideal S)).IsPrime) :
    I.IsPrime := by
  constructor
  · contrapose! h
    simp [is_prime_iff, h]
  · intro x y hxy
    have : (⟨x, 1⟩ : R × S) * ⟨y, 1⟩ ∈ Prod I ⊤ :=
      by
      rw [Prod.mk_mul_mk, mul_one, mem_prod]
      exact ⟨hxy, trivial⟩
    simpa using h.mem_or_mem this
#align ideal.is_prime_of_is_prime_prod_top Ideal.isPrime_of_isPrime_prod_top

/- warning: ideal.is_prime_of_is_prime_prod_top' -> Ideal.isPrime_of_isPrime_prod_top' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)}, (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.hasTop.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) I)) -> (Ideal.IsPrime.{u2} S (Ring.toSemiring.{u2} S _inst_2) I)
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)}, (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.instTopSubmodule.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) I)) -> (Ideal.IsPrime.{u2} S (Ring.toSemiring.{u2} S _inst_2) I)
Case conversion may be inaccurate. Consider using '#align ideal.is_prime_of_is_prime_prod_top' Ideal.isPrime_of_isPrime_prod_top'ₓ'. -/
theorem isPrime_of_isPrime_prod_top' {I : Ideal S} (h : (Ideal.prod (⊤ : Ideal R) I).IsPrime) :
    I.IsPrime := by
  apply @is_prime_of_is_prime_prod_top _ R
  rw [← map_prod_comm_prod]
  exact map_is_prime_of_equiv _
#align ideal.is_prime_of_is_prime_prod_top' Ideal.isPrime_of_isPrime_prod_top'

/- warning: ideal.is_prime_ideal_prod_top -> Ideal.isPrime_ideal_prod_top is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} [h : Ideal.IsPrime.{u1} R (Ring.toSemiring.{u1} R _inst_1) I], Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.hasTop.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} [h : Ideal.IsPrime.{u1} R (Ring.toSemiring.{u1} R _inst_1) I], Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.instTopSubmodule.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))
Case conversion may be inaccurate. Consider using '#align ideal.is_prime_ideal_prod_top Ideal.isPrime_ideal_prod_topₓ'. -/
theorem isPrime_ideal_prod_top {I : Ideal R} [h : I.IsPrime] : (prod I (⊤ : Ideal S)).IsPrime :=
  by
  constructor
  · rcases h with ⟨h, -⟩
    contrapose! h
    rw [← prod_top_top, Prod.ext_iff] at h
    exact h.1
  rintro ⟨r₁, s₁⟩ ⟨r₂, s₂⟩ ⟨h₁, h₂⟩
  cases' h.mem_or_mem h₁ with h h
  · exact Or.inl ⟨h, trivial⟩
  · exact Or.inr ⟨h, trivial⟩
#align ideal.is_prime_ideal_prod_top Ideal.isPrime_ideal_prod_top

/- warning: ideal.is_prime_ideal_prod_top' -> Ideal.isPrime_ideal_prod_top' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)} [h : Ideal.IsPrime.{u2} S (Ring.toSemiring.{u2} S _inst_2) I], Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.hasTop.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) I)
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)} [h : Ideal.IsPrime.{u2} S (Ring.toSemiring.{u2} S _inst_2) I], Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.instTopSubmodule.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) I)
Case conversion may be inaccurate. Consider using '#align ideal.is_prime_ideal_prod_top' Ideal.isPrime_ideal_prod_top'ₓ'. -/
theorem isPrime_ideal_prod_top' {I : Ideal S} [h : I.IsPrime] : (prod (⊤ : Ideal R) I).IsPrime :=
  by
  rw [← map_prod_comm_prod]
  apply map_is_prime_of_equiv _
  exact is_prime_ideal_prod_top
#align ideal.is_prime_ideal_prod_top' Ideal.isPrime_ideal_prod_top'

/- warning: ideal.ideal_prod_prime_aux -> Ideal.ideal_prod_prime_aux is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} {J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)}, (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) -> (Or (Eq.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) I (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.hasTop.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Eq.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) J (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.hasTop.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2))))))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] {I : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)} {J : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)}, (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 I J)) -> (Or (Eq.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) I (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.instTopSubmodule.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1))))) (Eq.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) J (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.instTopSubmodule.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2))))))
Case conversion may be inaccurate. Consider using '#align ideal.ideal_prod_prime_aux Ideal.ideal_prod_prime_auxₓ'. -/
theorem ideal_prod_prime_aux {I : Ideal R} {J : Ideal S} :
    (Ideal.prod I J).IsPrime → I = ⊤ ∨ J = ⊤ :=
  by
  contrapose!
  simp only [ne_top_iff_one, is_prime_iff, not_and, not_forall, not_or]
  exact fun ⟨hI, hJ⟩ hIJ => ⟨⟨0, 1⟩, ⟨1, 0⟩, by simp, by simp [hJ], by simp [hI]⟩
#align ideal.ideal_prod_prime_aux Ideal.ideal_prod_prime_aux

/- warning: ideal.ideal_prod_prime -> Ideal.ideal_prod_prime is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))), Iff (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) I) (Or (Exists.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (fun (p : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) => And (Ideal.IsPrime.{u1} R (Ring.toSemiring.{u1} R _inst_1) p) (Eq.{succ (max u1 u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) I (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 p (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.hasTop.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))))) (Exists.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (fun (p : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) => And (Ideal.IsPrime.{u2} S (Ring.toSemiring.{u2} S _inst_2) p) (Eq.{succ (max u1 u2)} (Ideal.{max u1 u2} (Prod.{u1, u2} R S) (Prod.semiring.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) I (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.hasTop.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) p)))))
but is expected to have type
  forall {R : Type.{u1}} {S : Type.{u2}} [_inst_1 : Ring.{u1} R] [_inst_2 : Ring.{u2} S] (I : Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))), Iff (Ideal.IsPrime.{max u1 u2} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2)) I) (Or (Exists.{succ u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (fun (p : Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) => And (Ideal.IsPrime.{u1} R (Ring.toSemiring.{u1} R _inst_1) p) (Eq.{max (succ u1) (succ u2)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) I (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 p (Top.top.{u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (Submodule.instTopSubmodule.{u2, u2} S S (Ring.toSemiring.{u2} S _inst_2) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} S (Semiring.toNonAssocSemiring.{u2} S (Ring.toSemiring.{u2} S _inst_2)))) (Semiring.toModule.{u2} S (Ring.toSemiring.{u2} S _inst_2)))))))) (Exists.{succ u2} (Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) (fun (p : Ideal.{u2} S (Ring.toSemiring.{u2} S _inst_2)) => And (Ideal.IsPrime.{u2} S (Ring.toSemiring.{u2} S _inst_2) p) (Eq.{max (succ u1) (succ u2)} (Ideal.{max u2 u1} (Prod.{u1, u2} R S) (Prod.instSemiringProd.{u1, u2} R S (Ring.toSemiring.{u1} R _inst_1) (Ring.toSemiring.{u2} S _inst_2))) I (Ideal.prod.{u1, u2} R S _inst_1 _inst_2 (Top.top.{u1} (Ideal.{u1} R (Ring.toSemiring.{u1} R _inst_1)) (Submodule.instTopSubmodule.{u1, u1} R R (Ring.toSemiring.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R _inst_1)))) p)))))
Case conversion may be inaccurate. Consider using '#align ideal.ideal_prod_prime Ideal.ideal_prod_primeₓ'. -/
/-- Classification of prime ideals in product rings: the prime ideals of `R × S` are precisely the
    ideals of the form `p × S` or `R × p`, where `p` is a prime ideal of `R` or `S`. -/
theorem ideal_prod_prime (I : Ideal (R × S)) :
    I.IsPrime ↔
      (∃ p : Ideal R, p.IsPrime ∧ I = Ideal.prod p ⊤) ∨
        ∃ p : Ideal S, p.IsPrime ∧ I = Ideal.prod ⊤ p :=
  by
  constructor
  · rw [ideal_prod_eq I]
    intro hI
    rcases ideal_prod_prime_aux hI with (h | h)
    · right
      rw [h] at hI⊢
      exact ⟨_, ⟨is_prime_of_is_prime_prod_top' hI, rfl⟩⟩
    · left
      rw [h] at hI⊢
      exact ⟨_, ⟨is_prime_of_is_prime_prod_top hI, rfl⟩⟩
  · rintro (⟨p, ⟨h, rfl⟩⟩ | ⟨p, ⟨h, rfl⟩⟩)
    · exact is_prime_ideal_prod_top
    · exact is_prime_ideal_prod_top'
#align ideal.ideal_prod_prime Ideal.ideal_prod_prime

end Ideal


import Mathlib.Tactic.FinCases

example {x : Nat} (h : x ∈ [0, 2, 37]) : x ≤ 57 := by
  fin_cases h
  repeat decide

example {x : Nat} (h : x ∈ [0, 2, 37]) : x = 0 ∨ x = 2 ∨ x = 37 := by
  fin_cases h
  repeat simp

example {x : Nat} (h : x ∈ List.range 5) : x ≤ 4 := by
  fin_cases h
  repeat decide

example {p : Fin 4 → Prop} (i : Fin 4) (h : p i) : p i := by
  fin_cases i
  repeat exact h

example (f : Nat → Prop) (p : Fin 3) (h0 : f 0) (h1 : f 1) (h2 : f 2) : f p.val := by
  fin_cases p
  all_goals
    assumption

example (f : Nat → Prop) (p : Fin 0) : f p.val :=
by fin_cases p

example (x2 : Fin 2) (x3 : Fin 3) : True := by
  fin_cases x2, x3
  all_goals trivial

-- TODO Restore the remaining tests from mathlib3:
-- Some of these test the `with` and `using` clauses which haven't been re-implemented.

example (x2 : Fin 2) (x3 : Fin 3) (n : Nat) (y : Fin n) : x2.val * x3.val = x3.val * x2.val := by
  fin_cases x2 <;> fin_cases x3
  fail_if_success
    fin_cases y
  all_goals rfl

-- example (x : ℕ) (h : x ∈ [2,3,5,7]) : True := by
--   fail_if_success
--     fin_cases h with [3,3,5,7]
--   trivial

-- example (x : List Nat) (h : x ∈ [[1],[2]]) : x.length = 1 := by
--   fin_cases h with [[1],[1+1]]
--   · simp
--   · guard_target = [1 + 1].length = 1
--     simp

--  -- testing that `with` arguments are elaborated with respect to the expected type:
-- example (x : Int) (h : x ∈ ([2,3] : List Int)) : x = 2 ∨ x = 3 := by
--   fin_cases h with [2,3]
--   all_goals { simp }

-- example (n : ℕ) (h : n % 3 ∈ [0,1]) : True := by
--   fin_cases h
--   · guard_hyp h : n % 3 = 0
--     trivial
--   · guard_hyp h : n % 3 = 1
--     trivial

-- instance (n : ℕ) : decidable (nat.prime n) := decidable_prime_1 n
-- example (x : ℕ) (h : x ∈ (List.range 10).filter Nat.prime) : x = 2 ∨ x = 3 ∨ x = 5 ∨ x = 7 := by
--   fin_cases h <;> decide

-- open equiv.perm
-- example (x : (Σ (a : fin 4), fin 4)) (h : x ∈ fin_pairs_lt 4) : x.1.val < 4 :=
-- begin
--   fin_cases h; simp,
--   any_goals { exact dec_trivial },
-- end

-- /-
-- In some circumstances involving `let`,
-- the temporary hypothesis that `fin_cases` creates does not get deleted.
-- We test that this is correctly named and that the name can be changed.

-- Note: after `fin_cases`, we have `this : (a : fin 3) = (0 : fin (2 + 1))`
-- for some reason. I don't know why, and it complicates the test.
-- -/
-- example (f : ℕ → fin 3) : true :=
-- begin
--   let a := f 3,
--   fin_cases a,
--   guard_hyp a := f 3,
--   guard_hyp this : a = (0 : fin (2 + 1)),
--   trivial, trivial,

--   let b := f 2,
--   fin_cases b using what,
--   guard_hyp what : b = (0 : fin (2 + 1)),

--   all_goals {trivial}
-- end

-- /-
-- The behavior above can be worked around with `fin_cases with`.
-- -/
-- example (f : ℕ → fin 3) : true :=
-- begin
--   let a := f 3,
--   fin_cases a with [0, 1, 2],
--   guard_hyp a := f 3,
--   guard_hyp this : a = 0,
--   trivial,
--   guard_hyp this : a = 1,
--   trivial,
--   guard_hyp this : a = 2,
--   let b := f 2,
--   fin_cases b with [0, 1, 2] using what,
--   guard_hyp what : b = 0,
--   all_goals {trivial}
-- end


namespace preorder
section preorder
variable T : Type

def is_upper_bound [preorder T] : set T -> T -> Prop :=
    λ S x, ∀ y, y ∈ S -> y ≤ x

structure Op := op :: (unop : T)
variable {T}

def op (x : T) : Op T := Op.op x
def unop (x : Op T) : T := Op.unop x
def op_rel (R : T -> T -> Prop) (x y : Op T) :=
    R (unop y) (unop x)

def op_refl
    {R : T -> T -> Prop}
    (H : ∀ x : T, R x x)
    : (∀ x, op_rel R x x)
:= begin unfold op_rel, exact (λ x, H (unop x)) end

def op_trans {R : T -> T -> Prop}
    : transitive R -> transitive (op_rel R) :=
begin intros H a b c
, unfold op_rel
, intros
, apply H
, all_goals {assumption}
end

def op_le [H : preorder T] := op_rel H.le

instance op_preorder [H : preorder T] : preorder (Op T) :=
{ le       := op_le
, le_refl  := op_refl H.le_refl
, le_trans := op_trans H.le_trans
}

variable {T}

def pointwise (R : T -> T -> Prop) {A} (f g : A -> T) :=
  ∀ x, R (f x) (g x)

private def pointwise_relf
  {R : T -> T -> Prop}
  (H : reflexive R) {A : Type} : reflexive (@pointwise _ R A) :=
  begin
  revert H,
  unfold reflexive pointwise,
  intros,
  apply H,
  end

private def pointwise_trans_helper
    (R : T -> T -> Prop) (H : ∀ ⦃ x y z ⦄, R x y -> R y z -> R x z)
    {A} {f h g : A -> T}
    (FG : ∀ x, R (f x) (g x))
    (GH : ∀ x, R (g x) (h x))
    := λ (a : A), H (FG a) (GH a)

private def pointwise_trans
  {R : T -> T -> Prop}
  (H : transitive R) {A : Type}
  : @transitive (A → T) (@pointwise T R A) :=
  begin intros
  , unfold transitive pointwise at *
  , intros
  , apply (pointwise_trans_helper R H a a_1)
  end

instance pointwise_preorder {A : Type} [H : preorder T]
  : preorder (A → T) :=
  { le := pointwise (λ a b, a ≤ b)
  , le_refl := begin apply (pointwise_relf H.le_refl) end
  , le_trans := pointwise_trans H.le_trans}

section functions_between
variables {A B : Type} [preorder A] [preorder B]
variables (f : A → B) (g : B -> A)

def monotonic :=
  ∀ x y, x ≤ y -> f x ≤ f y

variables (mf : monotonic f) (mg : monotonic g)

def are_adjoint := ∀ a b, f a ≤ b <-> a ≤ g b

infix `⊢`:30 := are_adjoint

def equiv [preorder T] (a b : T) := (a ≤ b) ∧ (b ≤ a)

infix `≃`:50 := equiv
def injective [preorder T] (R : A -> T -> Prop) :=
∀ a b c, R a b -> R a c -> b ≃ c

lemma right_adjoints_unique
    : injective (@are_adjoint A B _ _) :=
    begin intros f g h
    , unfold are_adjoint
    , intros fg fh
    , split; intro
    ,   { rewrite ← fh, rewrite fg}
    ,   { rewrite ← fg, rewrite fh}
    end
lemma left_adjoints_unique : injective (λ x y, @are_adjoint B A _ _ y x) :=
    begin intros h f g
    , unfold are_adjoint
    , intros fh gh
    , split; intro
    ,   { rewrite fh, rewrite ← gh}
    ,   { rewrite gh, rewrite ← fh}
    end
end functions_between

definition bounds_above [preorder T] (S : set T) (x : T) : Prop :=
    ∀ y, y ∈ S → y ≤ x

definition bounds_below [preorder T] (S : set T) (x : T) : Prop :=
  ∀ y : T, y ∈ S -> x ≤ y

end preorder
end preorder

open preorder

section
variable T : Type

def inclusion_trans
(a b c : set T)
(AB : a ⊆ b)
(BC : b ⊆ c)
: a ⊆ c := λ t tInA, BC (AB tInA)

instance set_inclusion : preorder (set T) :=
{ preorder . le := set.subset
, le_refl := λ A t inA, inA
, le_trans := inclusion_trans T
}

structure newtype (name : string) : Type :=
( old : T )

infix `!`:50 := newtype

structure equiv extends preorder T :=
    (symmetric : symmetric le)

structure partition :=
    (box : T -> set T)
    (correct : ∀ t s, t ∈ box s <-> box t = box s)

infix `⊞` : 60 := λ P x, partition.box P x

variable {T}

instance partition.part_box : has_coe_to_fun (partition T)
    :=
    { F := λ _, T → set T
    , coe := λ (P : partition T) x, P ⊞ x }

-- Note the switch of P and Q.
def refined_by (P Q : partition T) : Prop := forall x, Q.box x ≤ P.box x
def partition.indit (P : partition T) (x y : T) : Prop := y ∈ P x
def partition.dit (P : partition T) (x y : T) : Prop := y ∉ P x

instance partition_refinement : preorder (partition T) :=
{ le := refined_by
, le_refl := λ _ _ _ H, H
, le_trans := λ _ _ _ f g t _ x, f t (g t x)
}

class has_meet (T : Type) := (meet : T -> T -> T)

def meet [m : has_meet T] (a b : T) : T := has_meet.meet a b
notation `⊻`:50 := meet -- lean uses ∨ for the or

class has_top (T : Type) := (top : T)
def top {T} [t : has_top T] : T := t.top

class meet_lattice (T : Type) extends preorder T, has_meet T, has_top T :=
    (meet_greater : ∀ a b z : T, z ≤ a -> z ≤ b -> z ≤ meet a b)
    (meet_less_l : ∀ a b, meet a b ≤ a)
    (meet_less_r : ∀ a b, meet a b ≤ b)
    (top_greater : ∀ a, a ≤ top)

class has_join (T : Type) := {join : T -> T -> T}

def join [m : has_join T] (a b : T) : T := has_join.join a b
notation `⊼`:50 := join -- lean uses ∧ for the and Proposition

class has_bottom (T : Type) := (bottom : T)
def bottom {T:Type} [has_bottom T] : T := @has_bottom.bottom T _

class join_lattice (T : Type) extends preorder T, has_join T, has_bottom T :=
    (join_less : ∀ a b z, a ≤ z → b ≤ z -> join a b ≤ z)
    (join_greater_l : ∀ a b, a ≤ join a b )
    (join_greater_r : ∀ a b, b ≤ join a b )
    (bottom_less : ∀ a , bottom ≤ a)

class lattice extends preorder T: Type :=
(to_meet_lattice : meet_lattice T)
(to_join_lattice : join_lattice T)

end


/-
Copyright (c) 2018 Keji Neri, Blair Shi. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Blair Shi

-- This file aims to prove some theorems about eigenvalue and eigenvectors

* `is_eigenvalue` `is_eigenvector`: constructed eigenvalues and eigenvectors
in terms of linear map way

* `is_eigenvalue_M` `is_eigenvector_M`: constructed eigenvalues and eigenvectors
in terms of matrix way

-- Proved two ways are equivalent

* `is_diagonal_mat` : checked whether the given matrix is diagonal

-- currently working on Cayley-Hamilton Theorem
- Proved e • V = (e • I) * V, with e : F, V : vector F
-/

import .linear_map .ring_n_is_module_of_vector
import xenalib.Ellen_Arlt_matrix_rings
import xenalib.Keji_further_matrix_things

namespace M_module
instance mo {R : Type} {n : ℕ} [ring R] : module R (matrix R n 1) :=
{
  smul_add := @smul_add' _ _ 1 _,
  add_smul := @add_smul' _ _ 1 _,
  mul_smul := @mul_smul' _ _ 1 _,
  one_smul := @one_smul' _ _ 1 _,
}
end M_module

def mat_to_finite_free_module {F : Type} {n : ℕ} [ring F] (M : matrix F n 1) :
finite_free_module F n := λ I, M I 0

def finite_free_module_to_vec {F : Type} {n : ℕ} (fn : finite_free_module F n) :
vector F n := vector.of_fn fn

instance add_hommm {F : Type} [ring F] {n : nat}
: is_add_group_hom (@mat_to_finite_free_module F n _) :=
{
  add :=
  begin
    intros a b,
    unfold mat_to_finite_free_module,refl,
  end
}

def module_hom_mat_to_finite_free_module {F : Type} [ring F] {n : nat}
  : is_linear_map (@mat_to_finite_free_module F n _) :=
{
  smul :=
  begin
    intro c,
    intro x,
    unfold mat_to_finite_free_module,
    funext,
    refl,
  end,
  .. add_hommm
}

def mat_to_finite_free_module_is_linear {F : Type} [ring F] {n : nat}:
linear_map (matrix F n 1) (finite_free_module F n) :=
⟨mat_to_finite_free_module, module_hom_mat_to_finite_free_module⟩

def smul' {F : Type} {n : ℕ} [ring F] (M : matrix F n n) (fn : finite_free_module F n) :
finite_free_module F n := @mat_to_finite_free_module_is_linear F _ n (map_matrix.mat_mul_vec M (finite_free_module_to_vec fn))

theorem vector.nth_map {α β : Type*} {n : ℕ} (v : vector α n) (f : α → β) (m : fin n) :
  (v.map f).nth m = f (v.nth m) :=
begin
  cases v with l hl,
  unfold vector.nth vector.map,
  rw list.nth_le_map,
end

open M_module

open map_matrix

lemma smul_eq_smul_two {F : Type} {n : ℕ} [ring F] (fn : finite_free_module F n) :
∀ a : F, (smul a fn) =
mat_to_finite_free_module_is_linear.val
(@smul_M F _ _ _ a (vec_to_mat((finite_free_module_to_vec fn)))) :=
begin
intro a,
unfold mat_to_finite_free_module_is_linear,
simp,
unfold mat_to_finite_free_module,
unfold smul,
funext,
unfold smul_M,
unfold vec_to_mat,
unfold finite_free_module_to_vec,
simp,
end

def is_eigenvalue_M {F : Type*} {n : ℕ} [ring F] (M : matrix F n n ) (a : F) :=
∃ v : (finite_free_module F n), (v ≠ (0 : finite_free_module F n)) ∧ (smul' M v = smul a v)

def is_eigenvector_M {F : Type*} {n : ℕ} [ring F] (M : matrix F n n) (fn : finite_free_module F n) :=
∃ a : F, smul' M fn = smul a fn

def is_eigenvalue {F : Type*} {n : ℕ} [field F] [vector_space F (finite_free_module F n)]
(T : linear_map (finite_free_module F n) (finite_free_module F n)) (a : F) :=
∃ v : (finite_free_module F n) , (v ≠ (0 : (finite_free_module F n))) ∧ (T v = smul a v)

def is_eigenvector {F : Type*} {n : ℕ} [field F] [vector_space F (finite_free_module F n)]
(T : linear_map (finite_free_module F n) (finite_free_module F n)) (v : finite_free_module F n) (h : v ≠ (0 : finite_free_module F n)) :=
∃ a : F, T v = smul a v

namespace eigen
open function

-- def smul {R : Type} {n : nat} [ring R] (s : R) (rn : finite_free_module R n) :
-- finite_free_module R n := λ I, s * (rn I)

theorem finite_free_module_eq_vec {F : Type} [ring F] {n : nat} (fn : finite_free_module F n) :
∀ K, fn K = vector.nth (@finite_free_module_to_vec _ _ fn) K :=
begin
intro,
unfold finite_free_module_to_vec,
simp,
end

def finite_free_module_to_row_mat {F : Type} {n : ℕ} [ring F] (fn : finite_free_module F n) :
matrix F 1 n := λ I, λ J, fn J

def finite_free_module_to_col_mat {F : Type} {n : ℕ} [ring F] (fn : finite_free_module F n) :
matrix F n 1 := λ I, λ J, fn I

theorem finite_free_module_eq_col_mat {F : Type} [ring F] {n : nat} (fn : finite_free_module F n) :
∀ K, fn K = (finite_free_module_to_col_mat fn) K 0 :=
begin
intro,
unfold finite_free_module_to_col_mat,
end

theorem finite_free_module_eq_row_mat {F : Type} [ring F] {n : nat} (fn : finite_free_module F n) :
∀ K, fn K = (finite_free_module_to_row_mat fn) 0 K :=
begin
intro,
unfold finite_free_module_to_row_mat,
end

-- A : matrix F n n
-- The eigenvalues of TA are just those of A. (TA : Fn → Fn,TA(v) = Av)

open vector

instance {F : Type} {n : ℕ} [field F]: vector_space F (finite_free_module F n) := {}

open map_matrix

#check transpose_of_product

theorem eigen_map_equiv_one {F : Type} {n : ℕ} [field F] (M : matrix F n n) :
∀ eva : F, is_eigenvalue_M M eva ↔
@is_eigenvalue F n _ _ (@matrix_to_linear_map _ _ _ _ (Mᵀ)) eva :=
begin
intro,
split,
intro h₀,
unfold is_eigenvalue,
cases h₀ with v,
have h₁: v ≠ 0 ∧ (matrix_to_linear_map (Mᵀ)) v = smul eva v,
  cases h₀_h with h₀_hl h₀_hr,
  split,
  exact h₀_hl,
  unfold smul' at h₀_hr,
  unfold_coes at h₀_hr,
  unfold mat_to_finite_free_module_is_linear at h₀_hr,
  simp at h₀_hr,
  unfold mat_to_finite_free_module at h₀_hr,
  unfold map_matrix.mat_mul_vec at h₀_hr,
  unfold matrix.mul at h₀_hr,
  unfold map_matrix.vec_to_mat at h₀_hr,
  show (matrix_to_linear_map (Mᵀ)).1 v = smul eva v,
    unfold matrix_to_linear_map,
    simp,
    unfold matrix_to_map,
    rw ←h₀_hr,
    funext,
    simp only [(finite_free_module_eq_vec _ _).symm],
    conv in (v _ * (Mᵀ) _ i)
      begin
        rw [finite_free_module_eq_row_mat v _],
      end,
    conv in (M i _ * v _ )
      begin
        rw [finite_free_module_eq_col_mat v _],
      end,
    show (matrix.mul F (finite_free_module_to_row_mat v) (Mᵀ)) 0 i = _,
    show _ = matrix.mul F M (finite_free_module_to_col_mat v) i 0,
    show _ =(matrix.mul F M (finite_free_module_to_col_mat v))ᵀ 0 i,
    rw [transpose_of_product],
    have h₂ : (finite_free_module_to_row_mat v) = finite_free_module_to_col_mat vᵀ,
      unfold finite_free_module_to_row_mat,
      unfold finite_free_module_to_col_mat,
      funext,
      rw [transpose],
    rw [h₂],
    existsi v,
    exact h₁,

intro h₀,
unfold is_eigenvalue at h₀,
unfold is_eigenvalue_M,
cases h₀ with v,
have h₁ : v ≠ 0 ∧ smul' M v = smul eva v,
  split,
  cases h₀_h with h₀_hl h₀_hr,
  exact h₀_hl,
  unfold smul',
  cases h₀_h with h₀_hl h₀_hr,
  unfold_coes at h₀_hr,
  unfold matrix_to_linear_map at h₀_hr,
  simp at h₀_hr,
  unfold matrix_to_map at h₀_hr,
  unfold_coes,
  unfold mat_to_finite_free_module_is_linear,
  simp,
  unfold mat_to_finite_free_module,
  unfold mat_mul_vec,
  unfold vec_to_mat,
  unfold matrix.mul,
  unfold finite_free_module_to_vec,
  rw [← h₀_hr],
  funext,
  simp,
  conv in (v _ * (Mᵀ) _ I)
    begin
        rw [finite_free_module_eq_row_mat v _],
    end,
  conv in (M I _ * v _ )
    begin
      rw [finite_free_module_eq_col_mat v _],
    end,
  rw [eq_comm],
  show (matrix.mul F (finite_free_module_to_row_mat v) (Mᵀ)) 0 I = _,
  show _ = matrix.mul F M (finite_free_module_to_col_mat v) I 0,
  show _ =(matrix.mul F M (finite_free_module_to_col_mat v))ᵀ 0 I,
  rw [transpose_of_product],
  have h₂ : (finite_free_module_to_row_mat v) = finite_free_module_to_col_mat vᵀ,
    unfold finite_free_module_to_row_mat,
    unfold finite_free_module_to_col_mat,
    funext,
    rw [transpose],
  rw [h₂],
  existsi v,
  exact h₁,
end

end eigen

namespace Cayley_Hamilton

open eigen

theorem L0 {F : Type} [comm_ring F] {n : ℕ} (v : finite_free_module F n):
∀ eva : F, smul_M eva (vec_to_mat (finite_free_module_to_vec v)) =
matrix.mul F (smul_M eva (matrix.identity_matrix F)) (vec_to_mat (finite_free_module_to_vec v)) :=
begin
intro eva,
unfold smul_M,
unfold matrix.mul,
funext,
unfold matrix.identity_matrix,
unfold vec_to_mat,
unfold finite_free_module_to_vec,
simp,
conv in ( _ * _ * _)
begin
  rw [mul_assoc],
end,
conv
begin
  to_rhs,
  rw [← finset.mul_sum],
end,
congr,
rw [← @finset.sum_single _ _ _ _ (λ (x : fin n), ite (I = x) 1 0 * v x) I _],
simp,
intro J,
intro h,
funext,
simp,
split_ifs,
simp,
apply false.elim,
contradiction,
simp,
end

lemma sub_eq_sub {R : Type} [ring R] {a b : ℕ} (A B : matrix R a b) :
A - B = matrix.sub R A B :=
begin
refl,
end

@[simp] lemma val_eq_coe {α β γ : Type*} [ring α] [module α β] [module α γ]
  (f : linear_map β γ) : f.val = f := rfl

theorem L1 {R : Type} [comm_ring R] {n : ℕ} (M : matrix R n n) (v : finite_free_module R n):
∀ eva : R, (smul' M v = smul eva v) ↔
smul' (matrix.sub R M (smul_M eva (@matrix.identity_matrix R _ n))) v = (0 : finite_free_module R n) :=
begin
intro eva,
split,
intro h₀,
rw [← sub_eq_zero] at h₀,
unfold smul' at h₀,
unfold smul',
simp only [smul_eq_smul_two] at h₀,
unfold mat_mul_vec,
unfold mat_mul_vec at h₀,
rw val_eq_coe at h₀,
conv at h₀
begin
  to_lhs,
  rw ← @linear_map.map_sub _ _ _ _ _ _ (mat_to_finite_free_module_is_linear) _ _,
end,
have h₁ : matrix.sub R (matrix.mul R M (vec_to_mat (finite_free_module_to_vec v))) (smul_M eva (vec_to_mat (finite_free_module_to_vec v)))
= matrix.mul R (matrix.sub R M (smul_M eva (matrix.identity_matrix R))) (vec_to_mat (finite_free_module_to_vec v)),
  rw [← matrix.mul_sub_mul],
congr,
rw [L0],
conv at h₀ in (matrix.mul R M _ - smul_M eva _)
begin
  rw [sub_eq_sub],
  rw [h₁],
end,
exact h₀,

intro h₀,
rw [← sub_eq_zero],
unfold smul' at h₀,
unfold_coes at h₀,
unfold mat_mul_vec at h₀,
conv at h₀ in ((matrix.mul R (matrix.sub R _ _) _))
begin
  rw [← matrix.mul_sub_mul],
end,
unfold mat_to_finite_free_module_is_linear at h₀,
simp at h₀,
have h₁ :   mat_to_finite_free_module
      (matrix.sub R (matrix.mul R M (vec_to_mat (finite_free_module_to_vec v)))
         (matrix.mul R (smul_M eva (matrix.identity_matrix R)) (vec_to_mat (finite_free_module_to_vec v)))) =
    smul' M v - smul eva v,
    unfold smul',
    unfold smul,
    unfold mat_to_finite_free_module,
    unfold_coes,
    unfold mat_to_finite_free_module_is_linear,
    simp,
    unfold mat_to_finite_free_module,
    unfold matrix.sub,
    unfold mat_mul_vec,
    simp,
    funext,
    congr,
    unfold matrix.mul,
    unfold vec_to_mat,
    unfold finite_free_module_to_vec,
    simp,
    unfold smul_M,
    conv in (_ * _ * _)
    begin
      rw [mul_assoc],
    end,
    rw [← finset.mul_sum],
    congr,
    rw [eq_comm],
    unfold matrix.identity_matrix,
    rw [← @finset.sum_single _ _ _ _ (λ (x : fin n), ite (I = x) 1 0 * v x) I _],
    simp,
    intro J,
    intro h,
    funext,
    simp,
    split_ifs,
    simp,
    apply false.elim,
    contradiction,
    simp,
  rw [h₁] at h₀,
  exact h₀,
end

-- noncomputable def det_grl {R : Type} [comm_ring R] : Π {n : ℕ} (M : matrix R (n + 1) (n + 1))
-- (a : fin (n + 1)), R
-- | 0 M a := M 0 0
-- | (n + 1) M a :=
--   finset.sum finset.univ (λ (K : fin (n + 1)), M a K *
-- (((-1) ^ (a.val + K.val)) * (λ b : fin n, @det_grl n (minor M a.val K.val) b)))

-- theorem det_grl_eq_det {R : Type} [comm_ring R] :
-- ∀ n : ℕ, ∀ M : matrix R (n + 1) (n + 1), ∀ a : fin (n + 1),
-- det_grl M a = det M :=
-- begin
-- intros n M a,
-- unfold det,
-- unfold det_grl,

-- end

theorem L3 {R : Type} [comm_ring R] {n : ℕ} :
∀ a : R,
smul_M a (@matrix.identity_matrix _ _ n) = λ I J, if I = J then a else 0 :=
begin
intro a,
unfold smul_M,
funext,
unfold matrix.identity_matrix,
split_ifs,
rw [mul_one],
rw [mul_zero],
end

#check equiv.perm

theorem L2 {R : Type} [comm_ring R] {n : ℕ} (M : matrix R (n + 1) (n + 1)) :
smul_M (det M) (@matrix.identity_matrix _ _ (n + 1)) = matrix.mul R M (adj M) :=
begin
rw [L3],
funext,
unfold matrix.mul,
split_ifs,
unfold adj,
unfold transpose,
unfold cofactor,
unfold_coes,
unfold det,
unfold minor,
funext,
sorry
end

theorem Cayley_Hamilton {R : Type} [comm_ring R] {n : ℕ} (M : matrix R n n) :
∀ eva : R, @det n R _ (matrix.sub R M (smul_M eva (@matrix.identity_matrix R _ n))) = 0
↔ is_eigenvalue_M M eva :=
begin
intro,
split,
intro h₀,
show is_eigenvalue_M M eva,
sorry,

intro h₀,
unfold is_eigenvalue_M at h₀,
cases h₀ with v,
cases h₀_h with h₀_hl h₀_hl,
rw [L1] at h₀_hl,
sorry
end

end Cayley_Hamilton

namespace diagonal

def is_diagonal_mat {R : Type} [ring R] {n: ℕ} (M : matrix R n n) : Prop :=
∀ I J, (I ≠ J) → (M I J = 0)

-- Proposition 7.5. Suppose V is a f.d.v.s, and B = {v1, ..., vn} is a basis.
-- Suppose T : V → V is a linear map. Then,
-- [T]B is diagonal⇔v1,...,vn are eigenvectors of T

-- theorem diagonal_eigen_basis {R : Type} [ring R] {a b : ℕ} (M : )

-- Definition 7.6. If V is a f.d.v.s, and T : V → V is a linear map, say that T is diagonalisable if
-- there a basis of V consisting of eigenvectors of V .

-- Corollary 7.7. Suppose V is a f.d.v.s. with a basis B = {v1, ..., vn}. Suppose T : V → V is a
-- linear map. Then the following are equivalent: i T is diagonalisable
-- ii There is a basis C of V with [T]C is diagonal
-- iii There is an invertible n×n matrix P with P−1[T]BP a diagonal matrix

end diagonal


/-
Copyright (c) 2019 Bruno Bentzen. All rights reserved.
Released under the Apache License 2.0 (see "License");
Author: Bruno Bentzen
-/

import ..core.kan.coe ..core.connection.meet .groupoid.ops

open interval path

-- auxiliary definitions and lemmas

section

variable {A : Type}

private def f {a x y : A} (h : x = y) :
   path A a x → path A a y :=
λ p, eq.rec p h

private def f.eq {a x y : A} (h : x = y) (p : I → A) (h0 : p i0 = a)
  (hx : p i1 = x) (hy : p i1 = y) : f h (abs p h0 hx ) = abs p h0 hy :=
by unfold f; induction h; simp

variable (kan : has_hcom2 A)

private lemma aux {a b x : A} (p : path A a b) (h : b = x)
  (ha : p @@ i0 = a) (hx : p @@ i1 = x) : f h p = path.abs (app p) ha hx :=
by unfold f; induction h; simp; symmetry; apply pathdp.eta

private lemma aux' {a b : A} (p : path A a b) (ha : meet kan (app p) i1 i0 = a) (hb : meet kan (app p) i1 i1 = p @@ i1) :
  f ((app1 p).symm) p = abs (meet kan (path.app p) i1) ha hb :=
by revert ha hb; refine eq.rec _ (meet.face1j kan (app p)).symm; intros; apply aux

lemma family.eq {a x y: A} (p : path A a x) (q : path A a y) (h : x = y) (h' : f h p = q)
  {C : Π x : A, path A a x → Type} : C x p = C y q :=
by revert h'; unfold f; induction h; simp; intro; induction h'; refl

end

-- transport (coercion for paths)

section

variables {A : Type} (kan' : Π U, coe.has_coe U)

theorem path.transport {a x : A} (p : path A a x) (C : Π x : A, Type)
  (u : C a) : C x :=
have C0 : C (p @@ i0) = C a := by rw app0 p,
have C1 : C (p @@ i1) = C x := by rw app1 p,
eq.mp C1 ((kan' (λ i, C (p @@ i) )).coe i0 (eq.mp C0.symm u) i1)

end

-- based path induction

variables {A : Type} (kan : has_hcom2 A) (kan' : Π U, coe.has_coe U)

theorem path.induction {a x : A} {C : Π x : A, path A a x → Type}
  (p : path A a x) (u : C a (refl a)) : C x p :=
let X := path.abs (meet kan (app p) i0)
  (eq.trans (meet.face0j0i kan (app p)) (app0 p))
  (eq.trans (meet.face0j1i kan (app p)) rfl) in
have h : f ((app0 p).symm) (path.refl a) = X, from
begin
  rw refl.eq (eq.trans (meet.face0j kan (app p)) (funext (λ i, app0 p))),
  apply f.eq, transitivity, apply meet.face0j1i, apply app0
end,
let Y := abs (meet kan (app p) i1)
  (eq.trans (meet.face1j0i kan (app p)) (app0 p))
  (eq.trans (meet.face1j1i kan (app p)) rfl) in
have h' : f ((app1 p).symm) p = Y, from
begin
  symmetry, apply abs_irrel, symmetry, apply aux',
  apply (eq.trans (meet.face1j0i kan (app p)) (app0 p)),
  apply (eq.trans (meet.face1j1i kan (app p)) rfl)
end,
have C0 : C a (refl a) = C (p @@ i0) _ := family.eq _ _ (app0 p).symm h,
have C1 : C x p = C (p @@ i1) _ := family.eq p _ (app1 p).symm h',
eq.mp C1.symm ((kan' (λ i, C (p @@ i) (path.abs (meet kan (app p) i)
(eq.trans (meet.face0i' kan (app p) i) (app0 p) ) (meet.face1i' kan (app p) i) ))).coe
i0 (eq.mp C0 u) i1)

/-def C0 {a x : A} {C : Π x : A, path A a x → Type}
  (p : path A a x) : C a (path.refl a) = C (p @@ i0) _ :=
let X := path.abs (meet kan (app p) i0)
  (eq.trans (meet.face0j0i kan (app p)) (app0 p))
  (eq.trans (meet.face0j1i kan (app p)) rfl) in
have h : f ((app0 p).symm) (path.refl a) = X, from
begin
  rw refl.eq (eq.trans (meet.face0j kan (app p)) (funext (λ i, app0 p))),
  apply f.eq, transitivity, apply meet.face0j1i, apply app0
end,
family.eq _ _ (app0 p).symm h

variables {a x : A} {C : Π x : A, path A a x → Type}
  (p : path A a x) (u : C a (path.refl a))

#check @path.induction
#check @C0
#check (eq.mp (C0 kan (refl a)) u)

#check (kan' (λ i, C (p @@ i) (path.abs (meet kan (app p) i) (eq.trans (meet.face0i' kan (app p) i) (app0 p) ) (meet.face1i' kan (app p) i) ))).coeq
i0 (eq.mp (C0 kan p) u)

theorem path.induction.comp {a : A} {C : Π x : A, path A a x → Type} (u : C a (refl a)) :
  path (C a (refl a)) (path.induction kan kan' (path.refl a) u) u :=
begin
  fapply path.abs,
  --exact λ i, (kan' _).coe i0 i
end

-- eq.mp C1.symm (eq.mp C0 u) i1-/


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

Sigma types, aka dependent sum.
-/
import logic.cast
open inhabited sigma.ops
override eq.ops

namespace sigma
  universe variables u v
  variables {A A' : Type.{u}} {B : A → Type.{v}} {B' : A' → Type.{v}}

  definition unpack {C : (Σa, B a) → Type} {u : Σa, B a} (H : C ⟨u.1 , u.2⟩) : C u :=
  destruct u (λx y H, H) H

  theorem imp_sigma {C : A → Type} (H : ∀a, (B a → C a)) (p : Σa, B a) : Σa, C a :=
  destruct p (λa Hp, mk a (H a Hp))

  theorem dpair_heq {a : A} {a' : A'} {b : B a} {b' : B' a'}
      (HB : B == B') (Ha : a == a') (Hb : b == b') : ⟨a, b⟩ == ⟨a', b'⟩ :=
  hcongr_arg4 @mk (type_eq_of_heq Ha) HB Ha Hb

  protected theorem heq {p : Σa : A, B a} {p' : Σa' : A', B' a'} (HB : B == B') :
    ∀(H₁ : p.1 == p'.1) (H₂ : p.2 == p'.2), p == p' :=
  destruct p (take a₁ b₁, destruct p' (take a₂ b₂ H₁ H₂, dpair_heq HB H₁ H₂))

  protected definition is_inhabited [instance] [H₁ : inhabited A] [H₂ : inhabited (B (default A))] :
    inhabited (sigma B) :=
  inhabited.destruct H₁ (λa, inhabited.destruct H₂ (λb, inhabited.mk ⟨default A, b⟩))

  theorem eq_rec_dpair_commute {C : Πa, B a → Type} {a a' : A} (H : a = a') (b : B a) (c : C a b) :
      eq.rec_on H ⟨b, c⟩ = ⟨eq.rec_on H b, eq.rec_on (dcongr_arg2 C H rfl) c⟩ :=
  eq.drec_on H (dpair_eq rfl (!eq.rec_on_id⁻¹))

  variables {C : Πa, B a → Type} {D : Πa b, C a b → Type}

  definition dtrip (a : A) (b : B a) (c : C a b) := ⟨a, b, c⟩
  definition dquad (a : A) (b : B a) (c : C a b) (d : D a b c) := ⟨a, b, c, d⟩

  definition pr1' [reducible] (x : Σ a, B a) := x.1
  definition pr2' [reducible] (x : Σ a b, C a b) := x.2.1
  definition pr3  [reducible] (x : Σ a b, C a b) := x.2.2
  definition pr3' [reducible] (x : Σ a b c, D a b c) := x.2.2.1
  definition pr4  [reducible] (x : Σ a b c, D a b c) := x.2.2.2

  theorem dtrip_eq {a₁ a₂ : A} {b₁ : B a₁} {b₂ : B a₂} {c₁ : C a₁ b₁} {c₂ : C a₂ b₂}
      (H₁ : a₁ = a₂) (H₂ : eq.rec_on H₁ b₁ = b₂) (H₃ : cast (dcongr_arg2 C H₁ H₂) c₁ = c₂) :
    ⟨a₁, b₁, c₁⟩ = ⟨a₂, b₂, c₂⟩ :=
  dcongr_arg3 dtrip H₁ H₂ H₃

  theorem ndtrip_eq {A B : Type} {C : A → B → Type} {a₁ a₂ : A} {b₁ b₂ : B}
      {c₁ : C a₁ b₁} {c₂ : C a₂ b₂} (H₁ : a₁ = a₂) (H₂ : b₁ = b₂)
      (H₃ : cast (congr_arg2 C H₁ H₂) c₁ = c₂) : ⟨a₁, b₁, c₁⟩ = ⟨a₂, b₂, c₂⟩ :=
  hdcongr_arg3 dtrip H₁ (heq_of_eq H₂) H₃

  theorem ndtrip_equal {A B : Type} {C : A → B → Type} {p₁ p₂ : Σa b, C a b} :
      ∀(H₁ : pr1 p₁ = pr1 p₂) (H₂ : pr2' p₁ = pr2' p₂)
      (H₃ : eq.rec_on (congr_arg2 C H₁ H₂) (pr3 p₁) = pr3 p₂), p₁ = p₂ :=
  destruct p₁ (take a₁ q₁, destruct q₁ (take b₁ c₁, destruct p₂ (take a₂ q₂, destruct q₂
    (take b₂ c₂ H₁ H₂ H₃, ndtrip_eq H₁ H₂ H₃))))

end sigma