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

! This file was ported from Lean 3 source module data.mv_polynomial.comap
! 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.Data.MvPolynomial.Rename

/-!
# `comap` operation on `mv_polynomial`

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

This file defines the `comap` function on `mv_polynomial`.

`mv_polynomial.comap` is a low-tech example of a map of "algebraic varieties," modulo the fact that
`mathlib` does not yet define varieties.

## Notation

As in other polynomial files, we typically use the notation:

+ `σ : Type*` (indexing the variables)

+ `R : Type*` `[comm_semiring R]` (the coefficients)

-/

namespace MvPolynomial

variable {σ : Type _} {τ : Type _} {υ : Type _} {R : Type _} [CommSemiring R]

#print MvPolynomial.comap /-
/-- Given an algebra hom `f : mv_polynomial σ R →ₐ[R] mv_polynomial τ R`
and a variable evaluation `v : τ → R`,
`comap f v` produces a variable evaluation `σ → R`.
-/
noncomputable def comap (f : MvPolynomial σ R →ₐ[R] MvPolynomial τ R) : (τ → R) → σ → R :=
  fun x i => aeval x (f (X i))
#align mv_polynomial.comap MvPolynomial.comap
-/

/- warning: mv_polynomial.comap_apply -> MvPolynomial.comap_apply is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {τ : Type.{u2}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : AlgHom.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (x : τ -> R) (i : σ), Eq.{succ u3} R (MvPolynomial.comap.{u1, u2, u3} σ τ R _inst_1 f x i) (coeFn.{max (succ (max u2 u3)) (succ u3), max (succ (max u2 u3)) (succ u3)} (AlgHom.{u3, max u2 u3, u3} R (MvPolynomial.{u2, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) (fun (_x : AlgHom.{u3, max u2 u3, u3} R (MvPolynomial.{u2, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) => (MvPolynomial.{u2, u3} τ R _inst_1) -> R) ([anonymous].{u3, max u2 u3, u3} R (MvPolynomial.{u2, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) (MvPolynomial.aeval.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1) x) (coeFn.{max (succ (max u1 u3)) (succ (max u2 u3)), max (succ (max u1 u3)) (succ (max u2 u3))} (AlgHom.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (fun (_x : AlgHom.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) => (MvPolynomial.{u1, u3} σ R _inst_1) -> (MvPolynomial.{u2, u3} τ R _inst_1)) ([anonymous].{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) f (MvPolynomial.X.{u3, u1} R σ _inst_1 i)))
but is expected to have type
  forall {σ : Type.{u2}} {τ : Type.{u1}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : AlgHom.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (x : τ -> R) (i : σ), Eq.{succ u3} R (MvPolynomial.comap.{u2, u1, u3} σ τ R _inst_1 f x i) (FunLike.coe.{max (succ u1) (succ u3), max (succ u1) (succ u3), succ u3} (AlgHom.{u3, max u3 u1, u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) (MvPolynomial.{u1, u3} τ R _inst_1) (fun (_x : MvPolynomial.{u1, u3} τ R _inst_1) => (fun (x._@.Mathlib.Algebra.Hom.GroupAction._hyg.2186 : MvPolynomial.{u1, u3} τ R _inst_1) => R) _x) (SMulHomClass.toFunLike.{max u1 u3, u3, max u1 u3, u3} (AlgHom.{u3, max u3 u1, u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) R (MvPolynomial.{u1, u3} τ R _inst_1) R (SMulZeroClass.toSMul.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (AddMonoid.toZero.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))))) (DistribSMul.toSMulZeroClass.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (AddMonoid.toAddZeroClass.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))))) (DistribMulAction.toDistribSMul.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)))))) (Module.toDistribMulAction.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))) (Algebra.toModule.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))))))) (SMulZeroClass.toSMul.{u3, u3} R R (AddMonoid.toZero.{u3} R (AddCommMonoid.toAddMonoid.{u3} R (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1)))))) (DistribSMul.toSMulZeroClass.{u3, u3} R R (AddMonoid.toAddZeroClass.{u3} R (AddCommMonoid.toAddMonoid.{u3} R (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1)))))) (DistribMulAction.toDistribSMul.{u3, u3} R R (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (AddCommMonoid.toAddMonoid.{u3} R (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))))) (Module.toDistribMulAction.{u3, u3} R R (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1)))) (Algebra.toModule.{u3, u3} R R _inst_1 (CommSemiring.toSemiring.{u3} R _inst_1) (Algebra.id.{u3} R _inst_1)))))) (DistribMulActionHomClass.toSMulHomClass.{max u1 u3, u3, max u1 u3, u3} (AlgHom.{u3, max u3 u1, u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) R (MvPolynomial.{u1, u3} τ R _inst_1) R (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)))))) (AddCommMonoid.toAddMonoid.{u3} R (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))))) (Module.toDistribMulAction.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))) (Algebra.toModule.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (Module.toDistribMulAction.{u3, u3} R R (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1)))) (Algebra.toModule.{u3, u3} R R _inst_1 (CommSemiring.toSemiring.{u3} R _inst_1) (Algebra.id.{u3} R _inst_1))) (NonUnitalAlgHomClass.toDistribMulActionHomClass.{max u1 u3, u3, max u1 u3, u3} (AlgHom.{u3, max u3 u1, u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) R (MvPolynomial.{u1, u3} τ R _inst_1) R (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (Module.toDistribMulAction.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))) (Algebra.toModule.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (Module.toDistribMulAction.{u3, u3} R R (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u3} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u3} R (Semiring.toNonAssocSemiring.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1)))) (Algebra.toModule.{u3, u3} R R _inst_1 (CommSemiring.toSemiring.{u3} R _inst_1) (Algebra.id.{u3} R _inst_1))) (AlgHom.instNonUnitalAlgHomClassToMonoidToMonoidWithZeroToSemiringToNonUnitalNonAssocSemiringToNonAssocSemiringToNonUnitalNonAssocSemiringToNonAssocSemiringToDistribMulActionToAddCommMonoidToModuleToDistribMulActionToAddCommMonoidToModule.{u3, max u1 u3, u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1) (AlgHom.{u3, max u3 u1, u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)) (AlgHom.algHomClass.{u3, max u1 u3, u3} R (MvPolynomial.{u1, u3} τ R _inst_1) R _inst_1 (CommSemiring.toSemiring.{max u3 u1} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{u3} R _inst_1) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (Algebra.id.{u3} R _inst_1)))))) (MvPolynomial.aeval.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1) x) (FunLike.coe.{max (max (succ u2) (succ u1)) (succ u3), max (succ u2) (succ u3), max (succ u1) (succ u3)} (AlgHom.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (MvPolynomial.{u2, u3} σ R _inst_1) (fun (_x : MvPolynomial.{u2, u3} σ R _inst_1) => (fun (x._@.Mathlib.Algebra.Hom.GroupAction._hyg.2186 : MvPolynomial.{u2, u3} σ R _inst_1) => MvPolynomial.{u1, u3} τ R _inst_1) _x) (SMulHomClass.toFunLike.{max (max u2 u1) u3, u3, max u2 u3, max u1 u3} (AlgHom.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) (SMulZeroClass.toSMul.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (AddMonoid.toZero.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (AddCommMonoid.toAddMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1))))))) (DistribSMul.toSMulZeroClass.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (AddMonoid.toAddZeroClass.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (AddCommMonoid.toAddMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1))))))) (DistribMulAction.toDistribSMul.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (AddCommMonoid.toAddMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)))))) (Module.toDistribMulAction.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1))))) (Algebra.toModule.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))))))) (SMulZeroClass.toSMul.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (AddMonoid.toZero.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))))) (DistribSMul.toSMulZeroClass.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (AddMonoid.toAddZeroClass.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))))) (DistribMulAction.toDistribSMul.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)))))) (Module.toDistribMulAction.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))) (Algebra.toModule.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))))))) (DistribMulActionHomClass.toSMulHomClass.{max (max u2 u1) u3, u3, max u2 u3, max u1 u3} (AlgHom.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (AddCommMonoid.toAddMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)))))) (AddCommMonoid.toAddMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)))))) (Module.toDistribMulAction.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1))))) (Algebra.toModule.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (Module.toDistribMulAction.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))) (Algebra.toModule.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (NonUnitalAlgHomClass.toDistribMulActionHomClass.{max (max u2 u1) u3, u3, max u2 u3, max u1 u3} (AlgHom.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) (MonoidWithZero.toMonoid.{u3} R (Semiring.toMonoidWithZero.{u3} R (CommSemiring.toSemiring.{u3} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)))) (Module.toDistribMulAction.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (Semiring.toNonAssocSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1))))) (Algebra.toModule.{u3, max u2 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (Module.toDistribMulAction.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{u3} R _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (Semiring.toNonAssocSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1))))) (Algebra.toModule.{u3, max u1 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (AlgHom.instNonUnitalAlgHomClassToMonoidToMonoidWithZeroToSemiringToNonUnitalNonAssocSemiringToNonAssocSemiringToNonUnitalNonAssocSemiringToNonAssocSemiringToDistribMulActionToAddCommMonoidToModuleToDistribMulActionToAddCommMonoidToModule.{u3, max u2 u3, max u1 u3, max (max u2 u1) u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgHom.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.algHomClass.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))))))) f (MvPolynomial.X.{u3, u2} R σ _inst_1 i)))
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_apply MvPolynomial.comap_applyₓ'. -/
@[simp]
theorem comap_apply (f : MvPolynomial σ R →ₐ[R] MvPolynomial τ R) (x : τ → R) (i : σ) :
    comap f x i = aeval x (f (X i)) :=
  rfl
#align mv_polynomial.comap_apply MvPolynomial.comap_apply

/- warning: mv_polynomial.comap_id_apply -> MvPolynomial.comap_id_apply is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {R : Type.{u2}} [_inst_1 : CommSemiring.{u2} R] (x : σ -> R), Eq.{max (succ u1) (succ u2)} (σ -> R) (MvPolynomial.comap.{u1, u1, u2} σ σ R _inst_1 (AlgHom.id.{u2, max u1 u2} R (MvPolynomial.{u1, u2} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u2} (MvPolynomial.{u1, u2} σ R _inst_1) (MvPolynomial.commSemiring.{u2, u1} R σ _inst_1)) (MvPolynomial.algebra.{u2, u2, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u2} R _inst_1))) x) x
but is expected to have type
  forall {σ : Type.{u2}} {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (x : σ -> R), Eq.{max (succ u2) (succ u1)} (σ -> R) (MvPolynomial.comap.{u2, u2, u1} σ σ R _inst_1 (AlgHom.id.{u1, max u1 u2} R (MvPolynomial.{u2, u1} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u1} (MvPolynomial.{u2, u1} σ R _inst_1) (MvPolynomial.commSemiring.{u1, u2} R σ _inst_1)) (MvPolynomial.algebra.{u1, u1, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u1} R _inst_1))) x) x
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_id_apply MvPolynomial.comap_id_applyₓ'. -/
@[simp]
theorem comap_id_apply (x : σ → R) : comap (AlgHom.id R (MvPolynomial σ R)) x = x :=
  by
  funext i
  simp only [comap, AlgHom.id_apply, id.def, aeval_X]
#align mv_polynomial.comap_id_apply MvPolynomial.comap_id_apply

variable (σ R)

/- warning: mv_polynomial.comap_id -> MvPolynomial.comap_id is a dubious translation:
lean 3 declaration is
  forall (σ : Type.{u1}) (R : Type.{u2}) [_inst_1 : CommSemiring.{u2} R], Eq.{max (succ u1) (succ u2)} ((σ -> R) -> σ -> R) (MvPolynomial.comap.{u1, u1, u2} σ σ R _inst_1 (AlgHom.id.{u2, max u1 u2} R (MvPolynomial.{u1, u2} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u2} (MvPolynomial.{u1, u2} σ R _inst_1) (MvPolynomial.commSemiring.{u2, u1} R σ _inst_1)) (MvPolynomial.algebra.{u2, u2, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u2} R _inst_1)))) (id.{max (succ u1) (succ u2)} (σ -> R))
but is expected to have type
  forall (σ : Type.{u2}) (R : Type.{u1}) [_inst_1 : CommSemiring.{u1} R], Eq.{max (succ u2) (succ u1)} ((σ -> R) -> σ -> R) (MvPolynomial.comap.{u2, u2, u1} σ σ R _inst_1 (AlgHom.id.{u1, max u1 u2} R (MvPolynomial.{u2, u1} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u1} (MvPolynomial.{u2, u1} σ R _inst_1) (MvPolynomial.commSemiring.{u1, u2} R σ _inst_1)) (MvPolynomial.algebra.{u1, u1, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u1} R _inst_1)))) (id.{max (succ u2) (succ u1)} (σ -> R))
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_id MvPolynomial.comap_idₓ'. -/
theorem comap_id : comap (AlgHom.id R (MvPolynomial σ R)) = id :=
  by
  funext x
  exact comap_id_apply x
#align mv_polynomial.comap_id MvPolynomial.comap_id

variable {σ R}

/- warning: mv_polynomial.comap_comp_apply -> MvPolynomial.comap_comp_apply is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {τ : Type.{u2}} {υ : Type.{u3}} {R : Type.{u4}} [_inst_1 : CommSemiring.{u4} R] (f : AlgHom.{u4, max u1 u4, max u2 u4} R (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))) (g : AlgHom.{u4, max u2 u4, max u3 u4} R (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u3, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))) (x : υ -> R), Eq.{max (succ u1) (succ u4)} (σ -> R) (MvPolynomial.comap.{u1, u3, u4} σ υ R _inst_1 (AlgHom.comp.{u4, max u1 u4, max u2 u4, max u3 u4} R (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u3, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) g f) x) (MvPolynomial.comap.{u1, u2, u4} σ τ R _inst_1 f (MvPolynomial.comap.{u2, u3, u4} τ υ R _inst_1 g x))
but is expected to have type
  forall {σ : Type.{u3}} {τ : Type.{u2}} {υ : Type.{u1}} {R : Type.{u4}} [_inst_1 : CommSemiring.{u4} R] (f : AlgHom.{u4, max u4 u3, max u4 u2} R (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))) (g : AlgHom.{u4, max u4 u2, max u4 u1} R (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u1, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))) (x : υ -> R), Eq.{max (succ u3) (succ u4)} (σ -> R) (MvPolynomial.comap.{u3, u1, u4} σ υ R _inst_1 (AlgHom.comp.{u4, max u4 u3, max u2 u4, max u1 u4} R (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u1, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) g f) x) (MvPolynomial.comap.{u3, u2, u4} σ τ R _inst_1 f (MvPolynomial.comap.{u2, u1, u4} τ υ R _inst_1 g x))
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_comp_apply MvPolynomial.comap_comp_applyₓ'. -/
theorem comap_comp_apply (f : MvPolynomial σ R →ₐ[R] MvPolynomial τ R)
    (g : MvPolynomial τ R →ₐ[R] MvPolynomial υ R) (x : υ → R) :
    comap (g.comp f) x = comap f (comap g x) :=
  by
  funext i
  trans aeval x (aeval (fun i => g (X i)) (f (X i)))
  · apply eval₂_hom_congr rfl rfl
    rw [AlgHom.comp_apply]
    suffices g = aeval fun i => g (X i) by rw [← this]
    exact aeval_unique g
  · simp only [comap, aeval_eq_eval₂_hom, map_eval₂_hom, AlgHom.comp_apply]
    refine' eval₂_hom_congr _ rfl rfl
    ext r
    apply aeval_C
#align mv_polynomial.comap_comp_apply MvPolynomial.comap_comp_apply

/- warning: mv_polynomial.comap_comp -> MvPolynomial.comap_comp is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {τ : Type.{u2}} {υ : Type.{u3}} {R : Type.{u4}} [_inst_1 : CommSemiring.{u4} R] (f : AlgHom.{u4, max u1 u4, max u2 u4} R (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))) (g : AlgHom.{u4, max u2 u4, max u3 u4} R (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u3, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))), Eq.{max (max (succ u3) (succ u4)) (succ u1) (succ u4)} ((υ -> R) -> σ -> R) (MvPolynomial.comap.{u1, u3, u4} σ υ R _inst_1 (AlgHom.comp.{u4, max u1 u4, max u2 u4, max u3 u4} R (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u3, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) g f)) (Function.comp.{max (succ u3) (succ u4), max (succ u2) (succ u4), max (succ u1) (succ u4)} (υ -> R) (τ -> R) (σ -> R) (MvPolynomial.comap.{u1, u2, u4} σ τ R _inst_1 f) (MvPolynomial.comap.{u2, u3, u4} τ υ R _inst_1 g))
but is expected to have type
  forall {σ : Type.{u3}} {τ : Type.{u2}} {υ : Type.{u1}} {R : Type.{u4}} [_inst_1 : CommSemiring.{u4} R] (f : AlgHom.{u4, max u4 u3, max u4 u2} R (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))) (g : AlgHom.{u4, max u4 u2, max u4 u1} R (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u1, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1))), Eq.{max (max (succ u3) (succ u1)) (succ u4)} ((υ -> R) -> σ -> R) (MvPolynomial.comap.{u3, u1, u4} σ υ R _inst_1 (AlgHom.comp.{u4, max u4 u3, max u2 u4, max u1 u4} R (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.{u1, u4} υ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u3 u4} (MvPolynomial.{u3, u4} σ R _inst_1) (MvPolynomial.commSemiring.{u4, u3} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u4} (MvPolynomial.{u2, u4} τ R _inst_1) (MvPolynomial.commSemiring.{u4, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u4} (MvPolynomial.{u1, u4} υ R _inst_1) (MvPolynomial.commSemiring.{u4, u1} R υ _inst_1)) (MvPolynomial.algebra.{u4, u4, u3} R R σ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) (MvPolynomial.algebra.{u4, u4, u1} R R υ _inst_1 _inst_1 (Algebra.id.{u4} R _inst_1)) g f)) (Function.comp.{max (succ u4) (succ u1), max (succ u4) (succ u2), max (succ u4) (succ u3)} (υ -> R) (τ -> R) (σ -> R) (MvPolynomial.comap.{u3, u2, u4} σ τ R _inst_1 f) (MvPolynomial.comap.{u2, u1, u4} τ υ R _inst_1 g))
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_comp MvPolynomial.comap_compₓ'. -/
theorem comap_comp (f : MvPolynomial σ R →ₐ[R] MvPolynomial τ R)
    (g : MvPolynomial τ R →ₐ[R] MvPolynomial υ R) : comap (g.comp f) = comap f ∘ comap g :=
  by
  funext x
  exact comap_comp_apply _ _ _
#align mv_polynomial.comap_comp MvPolynomial.comap_comp

#print MvPolynomial.comap_eq_id_of_eq_id /-
theorem comap_eq_id_of_eq_id (f : MvPolynomial σ R →ₐ[R] MvPolynomial σ R) (hf : ∀ φ, f φ = φ)
    (x : σ → R) : comap f x = x := by
  convert comap_id_apply x
  ext1 φ
  rw [hf, AlgHom.id_apply]
#align mv_polynomial.comap_eq_id_of_eq_id MvPolynomial.comap_eq_id_of_eq_id
-/

/- warning: mv_polynomial.comap_rename -> MvPolynomial.comap_rename is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {τ : Type.{u2}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : σ -> τ) (x : τ -> R), Eq.{max (succ u1) (succ u3)} (σ -> R) (MvPolynomial.comap.{u1, u2, u3} σ τ R _inst_1 (MvPolynomial.rename.{u1, u2, u3} σ τ R _inst_1 f) x) (Function.comp.{succ u1, succ u2, succ u3} σ τ R x f)
but is expected to have type
  forall {σ : Type.{u3}} {τ : Type.{u1}} {R : Type.{u2}} [_inst_1 : CommSemiring.{u2} R] (f : σ -> τ) (x : τ -> R), Eq.{max (succ u3) (succ u2)} (σ -> R) (MvPolynomial.comap.{u3, u1, u2} σ τ R _inst_1 (MvPolynomial.rename.{u3, u1, u2} σ τ R _inst_1 f) x) (Function.comp.{succ u3, succ u1, succ u2} σ τ R x f)
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_rename MvPolynomial.comap_renameₓ'. -/
theorem comap_rename (f : σ → τ) (x : τ → R) : comap (rename f) x = x ∘ f :=
  by
  ext i
  simp only [rename_X, comap_apply, aeval_X]
#align mv_polynomial.comap_rename MvPolynomial.comap_rename

#print MvPolynomial.comapEquiv /-
/-- If two polynomial types over the same coefficient ring `R` are equivalent,
there is a bijection between the types of functions from their variable types to `R`.
-/
noncomputable def comapEquiv (f : MvPolynomial σ R ≃ₐ[R] MvPolynomial τ R) : (τ → R) ≃ (σ → R)
    where
  toFun := comap f
  invFun := comap f.symm
  left_inv := by
    intro x
    rw [← comap_comp_apply]
    apply comap_eq_id_of_eq_id
    intro
    simp only [AlgHom.id_apply, AlgEquiv.comp_symm]
  right_inv := by
    intro x
    rw [← comap_comp_apply]
    apply comap_eq_id_of_eq_id
    intro
    simp only [AlgHom.id_apply, AlgEquiv.symm_comp]
#align mv_polynomial.comap_equiv MvPolynomial.comapEquiv
-/

/- warning: mv_polynomial.comap_equiv_coe -> MvPolynomial.comapEquiv_coe is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {τ : Type.{u2}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))), Eq.{max (max (succ u2) (succ u3)) (succ u1) (succ u3)} ((fun (_x : Equiv.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (τ -> R) (σ -> R)) => (τ -> R) -> σ -> R) (MvPolynomial.comapEquiv.{u1, u2, u3} σ τ R _inst_1 f)) (coeFn.{max 1 (max (max (succ u2) (succ u3)) (succ u1) (succ u3)) (max (succ u1) (succ u3)) (succ u2) (succ u3), max (max (succ u2) (succ u3)) (succ u1) (succ u3)} (Equiv.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (τ -> R) (σ -> R)) (fun (_x : Equiv.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (τ -> R) (σ -> R)) => (τ -> R) -> σ -> R) (Equiv.hasCoeToFun.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (τ -> R) (σ -> R)) (MvPolynomial.comapEquiv.{u1, u2, u3} σ τ R _inst_1 f)) (MvPolynomial.comap.{u1, u2, u3} σ τ R _inst_1 ((fun (a : Sort.{max (succ (max u1 u3)) (succ (max u2 u3))}) (b : Sort.{max (succ (max u1 u3)) (succ (max u2 u3))}) [self : HasLiftT.{max (succ (max u1 u3)) (succ (max u2 u3)), max (succ (max u1 u3)) (succ (max u2 u3))} a b] => self.0) (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (HasLiftT.mk.{max (succ (max u1 u3)) (succ (max u2 u3)), max (succ (max u1 u3)) (succ (max u2 u3))} (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (CoeTCₓ.coe.{max (succ (max u1 u3)) (succ (max u2 u3)), max (succ (max u1 u3)) (succ (max u2 u3))} (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHomClass.coeTC.{u3, max u1 u3, max u2 u3, max (max u1 u3) u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgEquivClass.toAlgHomClass.{max (max u1 u3) u2 u3, u3, max u1 u3, max u2 u3} (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.algEquivClass.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))))))) f))
but is expected to have type
  forall {σ : Type.{u2}} {τ : Type.{u1}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : AlgEquiv.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))), Eq.{max (max (succ u2) (succ u1)) (succ u3)} (forall (a : τ -> R), (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : τ -> R) => σ -> R) a) (FunLike.coe.{max (max (succ u2) (succ u1)) (succ u3), max (succ u1) (succ u3), max (succ u2) (succ u3)} (Equiv.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (τ -> R) (σ -> R)) (τ -> R) (fun (_x : τ -> R) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : τ -> R) => σ -> R) _x) (Equiv.instFunLikeEquiv.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (τ -> R) (σ -> R)) (MvPolynomial.comapEquiv.{u2, u1, u3} σ τ R _inst_1 f)) (MvPolynomial.comap.{u2, u1, u3} σ τ R _inst_1 (AlgHomClass.toAlgHom.{u3, max u2 u3, max u1 u3, max (max u2 u1) u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgEquivClass.toAlgHomClass.{max (max u2 u1) u3, u3, max u2 u3, max u1 u3} (AlgEquiv.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.instAlgEquivClassAlgEquiv.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) f))
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_equiv_coe MvPolynomial.comapEquiv_coeₓ'. -/
@[simp]
theorem comapEquiv_coe (f : MvPolynomial σ R ≃ₐ[R] MvPolynomial τ R) :
    (comapEquiv f : (τ → R) → σ → R) = comap f :=
  rfl
#align mv_polynomial.comap_equiv_coe MvPolynomial.comapEquiv_coe

/- warning: mv_polynomial.comap_equiv_symm_coe -> MvPolynomial.comapEquiv_symm_coe is a dubious translation:
lean 3 declaration is
  forall {σ : Type.{u1}} {τ : Type.{u2}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))), Eq.{max (max (succ u1) (succ u3)) (succ u2) (succ u3)} ((fun (_x : Equiv.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (σ -> R) (τ -> R)) => (σ -> R) -> τ -> R) (Equiv.symm.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (τ -> R) (σ -> R) (MvPolynomial.comapEquiv.{u1, u2, u3} σ τ R _inst_1 f))) (coeFn.{max 1 (max (max (succ u1) (succ u3)) (succ u2) (succ u3)) (max (succ u2) (succ u3)) (succ u1) (succ u3), max (max (succ u1) (succ u3)) (succ u2) (succ u3)} (Equiv.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (σ -> R) (τ -> R)) (fun (_x : Equiv.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (σ -> R) (τ -> R)) => (σ -> R) -> τ -> R) (Equiv.hasCoeToFun.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (σ -> R) (τ -> R)) (Equiv.symm.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (τ -> R) (σ -> R) (MvPolynomial.comapEquiv.{u1, u2, u3} σ τ R _inst_1 f))) (MvPolynomial.comap.{u2, u1, u3} τ σ R _inst_1 ((fun (a : Sort.{max (succ (max u2 u3)) (succ (max u1 u3))}) (b : Sort.{max (succ (max u2 u3)) (succ (max u1 u3))}) [self : HasLiftT.{max (succ (max u2 u3)) (succ (max u1 u3)), max (succ (max u2 u3)) (succ (max u1 u3))} a b] => self.0) (AlgEquiv.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (HasLiftT.mk.{max (succ (max u2 u3)) (succ (max u1 u3)), max (succ (max u2 u3)) (succ (max u1 u3))} (AlgEquiv.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (CoeTCₓ.coe.{max (succ (max u2 u3)) (succ (max u1 u3)), max (succ (max u2 u3)) (succ (max u1 u3))} (AlgEquiv.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHom.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgHomClass.coeTC.{u3, max u2 u3, max u1 u3, max (max u2 u3) u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgEquivClass.toAlgHomClass.{max (max u2 u3) u1 u3, u3, max u2 u3, max u1 u3} (AlgEquiv.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.algEquivClass.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.{u1, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))))))) (AlgEquiv.symm.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.{u2, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R σ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) f)))
but is expected to have type
  forall {σ : Type.{u2}} {τ : Type.{u1}} {R : Type.{u3}} [_inst_1 : CommSemiring.{u3} R] (f : AlgEquiv.{u3, max u3 u2, max u3 u1} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))), Eq.{max (max (succ u2) (succ u1)) (succ u3)} (forall (a : σ -> R), (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : σ -> R) => τ -> R) a) (FunLike.coe.{max (max (succ u2) (succ u1)) (succ u3), max (succ u2) (succ u3), max (succ u1) (succ u3)} (Equiv.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (σ -> R) (τ -> R)) (σ -> R) (fun (_x : σ -> R) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : σ -> R) => τ -> R) _x) (Equiv.instFunLikeEquiv.{max (succ u2) (succ u3), max (succ u1) (succ u3)} (σ -> R) (τ -> R)) (Equiv.symm.{max (succ u1) (succ u3), max (succ u2) (succ u3)} (τ -> R) (σ -> R) (MvPolynomial.comapEquiv.{u2, u1, u3} σ τ R _inst_1 f))) (MvPolynomial.comap.{u1, u2, u3} τ σ R _inst_1 (AlgHomClass.toAlgHom.{u3, max u1 u3, max u2 u3, max (max u2 u1) u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) (AlgEquivClass.toAlgHomClass.{max (max u2 u1) u3, u3, max u1 u3, max u2 u3} (AlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1))) R (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (AlgEquiv.instAlgEquivClassAlgEquiv.{u3, max u1 u3, max u2 u3} R (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.{u2, u3} σ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)))) (AlgEquiv.symm.{u3, max u2 u3, max u1 u3} R (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.{u1, u3} τ R _inst_1) _inst_1 (CommSemiring.toSemiring.{max u2 u3} (MvPolynomial.{u2, u3} σ R _inst_1) (MvPolynomial.commSemiring.{u3, u2} R σ _inst_1)) (CommSemiring.toSemiring.{max u1 u3} (MvPolynomial.{u1, u3} τ R _inst_1) (MvPolynomial.commSemiring.{u3, u1} R τ _inst_1)) (MvPolynomial.algebra.{u3, u3, u2} R R σ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) (MvPolynomial.algebra.{u3, u3, u1} R R τ _inst_1 _inst_1 (Algebra.id.{u3} R _inst_1)) f)))
Case conversion may be inaccurate. Consider using '#align mv_polynomial.comap_equiv_symm_coe MvPolynomial.comapEquiv_symm_coeₓ'. -/
@[simp]
theorem comapEquiv_symm_coe (f : MvPolynomial σ R ≃ₐ[R] MvPolynomial τ R) :
    ((comapEquiv f).symm : (σ → R) → τ → R) = comap f.symm :=
  rfl
#align mv_polynomial.comap_equiv_symm_coe MvPolynomial.comapEquiv_symm_coe

end MvPolynomial


/-
  Stalk of rings.

  https://stacks.math.columbia.edu/tag/007L
  (just says that the category of rings is a type of algebraic structure)

  Author -- Ramon Fernandez Mir
-/

import topology.basic
import sheaves.stalk
import sheaves.presheaf_of_rings

universes u v w

open topological_space

section stalk_of_rings

variables {α : Type u} [topological_space α]
variables (F : presheaf_of_rings α) (x : α)

definition stalk_of_rings := stalk F.to_presheaf x

end stalk_of_rings

-- Stalks are rings.

section stalk_of_rings_is_ring

parameters {α : Type u} [topological_space α]
parameters (F : presheaf_of_rings α) (x : α)

-- Add.

private def stalk_of_rings_add_aux :
stalk.elem F.to_presheaf x →
stalk.elem F.to_presheaf x →
stalk F.to_presheaf x :=
λ s t,
⟦{U := s.U ∩ t.U,
HxU := ⟨s.HxU, t.HxU⟩,
s := F.res s.U _ (set.inter_subset_left _ _) s.s +
     F.res t.U _ (set.inter_subset_right _ _) t.s}⟧

instance stalk_of_rings_has_add : has_add (stalk_of_rings F x) :=
{ add := quotient.lift₂ (stalk_of_rings_add_aux) $
  begin
    intros a1 a2 b1 b2 H1 H2,
    let F' := F.to_presheaf,
    rcases H1 with ⟨U1, ⟨HxU1, ⟨HU1a1U, HU1b1U, HresU1⟩⟩⟩,
    rcases H2 with ⟨U2, ⟨HxU2, ⟨HU2a2U, HU2b2U, HresU2⟩⟩⟩,
    apply quotient.sound,
    use [U1 ∩ U2, ⟨HxU1, HxU2⟩],
    use [set.inter_subset_inter HU1a1U HU2a2U, set.inter_subset_inter HU1b1U HU2b2U],
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    have HresU1' :
        (F'.res U1 (U1 ∩ U2) (set.inter_subset_left _ _) ((F'.res a1.U U1 HU1a1U) (a1.s))) =
        (F'.res U1 (U1 ∩ U2) (set.inter_subset_left _ _) ((F'.res b1.U U1 HU1b1U) (b1.s)))
    := by rw HresU1,
    have HresU2' :
        (F'.res U2 (U1 ∩ U2) (set.inter_subset_right _ _) ((F'.res a2.U U2 HU2a2U) (a2.s))) =
        (F'.res U2 (U1 ∩ U2) (set.inter_subset_right _ _) ((F'.res b2.U U2 HU2b2U) (b2.s)))
    := by rw HresU2,
    repeat { rw ←(presheaf.Hcomp' F') at HresU1' },
    repeat { rw ←(presheaf.Hcomp' F') at HresU2' },
    repeat { rw ←(presheaf.Hcomp' F') },
    rw [HresU1', HresU2'],
  end }

instance stalk_of_rings_add_semigroup : add_semigroup (stalk_of_rings F x) :=
{ add := stalk_of_rings_has_add.add,
  add_assoc :=
  begin
    intros a b c,
    refine quotient.induction_on₃ a b c _,
    rintros ⟨U, HxU, sU⟩ ⟨V, HxV, sV⟩ ⟨W, HxW, sW⟩,
    have HUVWsub : U ∩ V ∩ W ⊆ U ∩ (V ∩ W)
    := λ x ⟨⟨HxU, HxV⟩, HxW⟩, ⟨HxU, ⟨HxV, HxW⟩⟩,
    apply quotient.sound,
    use [U ∩ V ∩ W, ⟨⟨HxU, HxV⟩, HxW⟩],
    use [set.subset.refl _, HUVWsub],
    dsimp,
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { erw ←presheaf.Hcomp' },
    rw add_assoc,
  end }

instance stalk_of_rings_add_comm_semigroup : add_comm_semigroup (stalk_of_rings F x) :=
{ add_comm :=
  begin
    intros a b,
    refine quotient.induction_on₂ a b _,
    rintros ⟨U, HxU, sU⟩ ⟨V, HxV, sV⟩,
    apply quotient.sound,
    have HUVUV : U ∩ V ⊆ U ∩ V := λ x HxUV, HxUV,
    have HUVVU : U ∩ V ⊆ V ∩ U := λ x ⟨HxU, HxV⟩, ⟨HxV, HxU⟩,
    use [U ∩ V, ⟨HxU, HxV⟩, HUVUV, HUVVU],
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    rw add_comm,
  end,
  ..stalk_of_rings_add_semigroup }

-- Zero.

private def stalk_of_rings_zero : stalk_of_rings F x :=
⟦{U := opens.univ, HxU := trivial, s:= 0}⟧

instance stalk_of_rings_has_zero : has_zero (stalk_of_rings F x) :=
{ zero := stalk_of_rings_zero }

instance stalk_of_rings_add_comm_monoid : add_comm_monoid (stalk_of_rings F x) :=
{ zero := stalk_of_rings_zero,
  zero_add :=
  begin
    intros a,
    refine quotient.induction_on a _,
    rintros ⟨U, HxU, sU⟩,
    apply quotient.sound,
    have HUsub : U ⊆ opens.univ ∩ U := λ x HxU, ⟨trivial, HxU⟩,
    use [U, HxU, HUsub, set.subset.refl U],
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    erw (is_ring_hom.map_zero ((F.to_presheaf).res _ _ _));
    try { apply_instance },
    rw zero_add,
    refl,
  end,
  add_zero :=
  begin
    intros a,
    refine quotient.induction_on a _,
    rintros ⟨U, HxU, sU⟩,
    apply quotient.sound,
    have HUsub : U ⊆ U ∩ opens.univ := λ x HxU, ⟨HxU, trivial⟩,
    use [U, HxU, HUsub, set.subset.refl U],
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { erw ←presheaf.Hcomp' },
    dsimp,
    erw (is_ring_hom.map_zero ((F.to_presheaf).res _ _ _));
    try { apply_instance },
    rw add_zero,
    refl,
  end,
  ..stalk_of_rings_add_comm_semigroup }

-- Neg.

private def stalk_sub_aux :
stalk.elem F.to_presheaf x →
stalk F.to_presheaf x :=
λ s, ⟦{U := s.U, HxU := s.HxU, s := -s.s}⟧

instance stalk_of_rings_has_neg : has_neg (stalk_of_rings F x) :=
{ neg := quotient.lift stalk_sub_aux $
  begin
    intros a b H,
    rcases H with ⟨U, ⟨HxU, ⟨HUaU, HUbU, HresU⟩⟩⟩,
    apply quotient.sound,
    use [U, HxU, HUaU, HUbU],
    repeat { rw @is_ring_hom.map_neg _ _ _ _ _ (F.res_is_ring_hom _ _ _) },
    rw HresU,
  end }

instance stalk_of_rings_add_comm_group : add_comm_group (stalk_of_rings F x) :=
{ neg := stalk_of_rings_has_neg.neg,
  add_left_neg :=
  begin
    intros a,
    refine quotient.induction_on a _,
    rintros ⟨U, HxU, sU⟩,
    apply quotient.sound,
    have HUUU : U ⊆ U ∩ U := λ x HxU, ⟨HxU, HxU⟩,
    have HUuniv : U ⊆ opens.univ := λ x HxU, trivial,
    use [U, HxU, HUUU, HUuniv],
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    erw (is_ring_hom.map_neg ((F.to_presheaf).res _ _ _));
    try { apply_instance },
    rw add_left_neg,
    erw (is_ring_hom.map_zero ((F.to_presheaf).res _ _ _));
    try { apply_instance },
  end,
  ..stalk_of_rings_add_comm_monoid }

-- Mul.

private def stalk_of_rings_mul_aux :
stalk.elem F.to_presheaf x →
stalk.elem F.to_presheaf x →
stalk F.to_presheaf x :=
λ s t,
⟦{U := s.U ∩ t.U,
HxU := ⟨s.HxU, t.HxU⟩,
s := F.res s.U _ (set.inter_subset_left _ _) s.s *
     F.res t.U _ (set.inter_subset_right _ _) t.s}⟧

instance stalk_of_rings_has_mul : has_mul (stalk_of_rings F x) :=
{ mul := quotient.lift₂ (stalk_of_rings_mul_aux) $
  begin
    intros a1 a2 b1 b2 H1 H2,
    let F' := F.to_presheaf,
    rcases H1 with ⟨U1, ⟨HxU1, ⟨HU1a1U, HU1b1U, HresU1⟩⟩⟩,
    rcases H2 with ⟨U2, ⟨HxU2, ⟨HU2a2U, HU2b2U, HresU2⟩⟩⟩,
    apply quotient.sound,
    use [U1 ∩ U2, ⟨HxU1, HxU2⟩],
    use [set.inter_subset_inter HU1a1U HU2a2U, set.inter_subset_inter HU1b1U HU2b2U],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    have HresU1' :
        (F'.res U1 (U1 ∩ U2) (set.inter_subset_left _ _) ((F'.res a1.U U1 HU1a1U) (a1.s))) =
        (F'.res U1 (U1 ∩ U2) (set.inter_subset_left _ _) ((F'.res b1.U U1 HU1b1U) (b1.s)))
    := by rw HresU1,
    have HresU2' :
        (F'.res U2 (U1 ∩ U2) (set.inter_subset_right _ _) ((F'.res a2.U U2 HU2a2U) (a2.s))) =
        (F'.res U2 (U1 ∩ U2) (set.inter_subset_right _ _) ((F'.res b2.U U2 HU2b2U) (b2.s)))
    := by rw HresU2,
    repeat { rw ←(presheaf.Hcomp' F') at HresU1' },
    repeat { rw ←(presheaf.Hcomp' F') at HresU2' },
    repeat { rw ←(presheaf.Hcomp' F') },
    rw [HresU1', HresU2'],
  end }

instance stalk_of_rings_mul_semigroup : semigroup (stalk_of_rings F x) :=
{ mul := stalk_of_rings_has_mul.mul,
  mul_assoc :=
  begin
    intros a b c,
    refine quotient.induction_on₃ a b c _,
    rintros ⟨U, HxU, sU⟩ ⟨V, HxV, sV⟩ ⟨W, HxW, sW⟩,
    have HUVWsub : U ∩ V ∩ W ⊆ U ∩ (V ∩ W)
    := λ x ⟨⟨HxU, HxV⟩, HxW⟩, ⟨HxU, ⟨HxV, HxW⟩⟩,
    apply quotient.sound,
    use [U ∩ V ∩ W, ⟨⟨HxU, HxV⟩, HxW⟩],
    use [set.subset.refl _, HUVWsub],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw ←presheaf.Hcomp' },
    rw mul_assoc,
  end }

instance stalk_of_rings_mul_comm_semigroup : comm_semigroup (stalk_of_rings F x) :=
{ mul_comm :=
  begin
    intros a b,
    refine quotient.induction_on₂ a b _,
    rintros ⟨U, HxU, sU⟩ ⟨V, HxV, sV⟩,
    apply quotient.sound,
    have HUVUV : U ∩ V ⊆ U ∩ V := λ x HxUV, HxUV,
    have HUVVU : U ∩ V ⊆ V ∩ U := λ x ⟨HxU, HxV⟩, ⟨HxV, HxU⟩,
    use [U ∩ V, ⟨HxU, HxV⟩, HUVUV, HUVVU],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw ←presheaf.Hcomp' },
    rw mul_comm,
  end,
  ..stalk_of_rings_mul_semigroup }

-- One.

private def stalk_of_rings_one : stalk_of_rings F x :=
⟦{U := opens.univ, HxU := trivial, s:= 1}⟧

instance stalk_of_rings_has_one : has_one (stalk_of_rings F x) :=
{ one := stalk_of_rings_one }

instance stalk_of_rings_mul_comm_monoid : comm_monoid (stalk_of_rings F x) :=
{ one := stalk_of_rings_one,
  one_mul :=
  begin
    intros a,
    refine quotient.induction_on a _,
    rintros ⟨U, HxU, sU⟩,
    apply quotient.sound,
    have HUsub : U ⊆ opens.univ ∩ U := λ x HxU, ⟨trivial, HxU⟩,
    use [U, HxU, HUsub, set.subset.refl U],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw ←presheaf.Hcomp' },
    erw (is_ring_hom.map_one ((F.to_presheaf).res _ _ _));
    try { apply_instance },
    rw one_mul,
    refl,
  end,
  mul_one :=
  begin
    intros a,
    refine quotient.induction_on a _,
    rintros ⟨U, HxU, sU⟩,
    apply quotient.sound,
    have HUsub : U ⊆ U ∩ opens.univ := λ x HxU, ⟨HxU, trivial⟩,
    use [U, HxU, HUsub, set.subset.refl U],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw ←presheaf.Hcomp' },
    dsimp,
    erw (is_ring_hom.map_one ((F.to_presheaf).res _ _ _));
    try { apply_instance },
    rw mul_one,
    refl,
  end,
  ..stalk_of_rings_mul_comm_semigroup }

-- Ring.

instance stalk_of_rings_is_comm_ring : comm_ring (stalk_of_rings F x) :=
{ left_distrib :=
  begin
    intros a b c,
    refine quotient.induction_on₃ a b c _,
    rintros ⟨U, HxU, sU⟩ ⟨V, HxV, sV⟩ ⟨W, HxW, sW⟩,
    have HUVWsub : U ∩ V ∩ W ⊆ U ∩ (V ∩ W)
    := λ x ⟨⟨HxU, HxV⟩, HxW⟩, ⟨HxU, ⟨HxV, HxW⟩⟩,
    have HUVWsub2 : U ∩ V ∩ W ⊆ U ∩ V ∩ (U ∩ W)
    := λ x ⟨⟨HxU, HxV⟩, HxW⟩, ⟨⟨HxU, HxV⟩, ⟨HxU, HxW⟩⟩,
    apply quotient.sound,
    use [U ∩ V ∩ W, ⟨⟨HxU, HxV⟩, HxW⟩, HUVWsub, HUVWsub2],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    rw mul_add,
  end,
  right_distrib :=
  begin
    intros a b c,
    refine quotient.induction_on₃ a b c _,
    rintros ⟨U, HxU, sU⟩ ⟨V, HxV, sV⟩ ⟨W, HxW, sW⟩,
    have HUVWrfl : U ∩ V ∩ W ⊆ U ∩ V ∩ W := λ x Hx, Hx,
    have HUVWsub : U ∩ V ∩ W ⊆ U ∩ W ∩ (V ∩ W)
    := λ x ⟨⟨HxU, HxV⟩, HxW⟩, ⟨⟨HxU, HxW⟩, ⟨HxV, HxW⟩⟩,
    apply quotient.sound,
    use [U ∩ V ∩ W, ⟨⟨HxU, HxV⟩, HxW⟩, HUVWrfl, HUVWsub],
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    repeat { rw (F.res_is_ring_hom _ _ _).map_mul },
    repeat { rw (F.res_is_ring_hom _ _ _).map_add },
    repeat { rw ←presheaf.Hcomp' },
    rw add_mul,
  end,
  ..stalk_of_rings_add_comm_group,
  ..stalk_of_rings_mul_comm_monoid }

end stalk_of_rings_is_ring

-- Stalks are colimits.

section stalk_colimit

variables {α : Type u} [topological_space α]
variables (F : presheaf_of_rings α) (x : α)

variables (S : Type w) [comm_ring S] [decidable_eq S]
variables (G : Π U, x ∈ U → F.F U → S) [HG : ∀ U, ∀ (h : x ∈ U), is_ring_hom (G U h)]
variables (hg : ∀ U V (H : U ⊆ V) r, ∀ (h : x ∈ U), G U h (F.res V U H r) = G V (H h) r)

def to_stalk (U : opens α) (HxU : x ∈ U) (s : F.F U) : stalk_of_rings F x
:= ⟦{U := U, HxU := HxU, s := s}⟧

instance to_stalk.is_ring_hom (U) (HxU) : is_ring_hom (to_stalk F x U HxU) :=
{ map_one := quotient.sound $ ⟨U, HxU, set.subset.refl _, λ x Hx, trivial,
    begin
        erw (F.res_is_ring_hom _ _ _).map_one,
        erw (F.res_is_ring_hom _ _ _).map_one,
    end⟩,
  map_add := λ y z, quotient.sound $ ⟨U, HxU, set.subset.refl _, λ x Hx, ⟨Hx, Hx⟩,
    begin
        erw ←(F.res_is_ring_hom _ _ _).map_add,
        erw presheaf.Hcomp',
    end⟩,
  map_mul := λ y z, quotient.sound $ ⟨U, HxU, set.subset.refl _, λ x Hx, ⟨Hx, Hx⟩,
    begin
        erw ←(F.res_is_ring_hom _ _ _).map_mul,
        erw presheaf.Hcomp',
    end⟩ }

include hg

protected def to_stalk.rec (y : stalk_of_rings F x) : S :=
quotient.lift_on' y (λ Us, G Us.1 Us.2 Us.3) $
λ ⟨U, HxU, s⟩ ⟨V, HxV, t⟩ ⟨W, HxW, HWU, HWV, Hres⟩,
begin
    dsimp,
    erw [←hg W U HWU s HxW, ←hg W V HWV t HxW, Hres],
end
/-
to_stalk.rec : Π {α : Type u} [_inst_1 : topological_space α] (F : presheaf_of_rings α) (x : α) (S : Type w) [_inst_2 : comm_ring S] [_inst_3 : decidable_eq S] (G : Π (U : opens α), (F.to_presheaf).F U → S), (∀ (U V : opens α) (H : U ⊆ V) (r : (F.to_presheaf).F V), G U ((F.to_presheaf).res V U H r) = G V r) → stalk_of_rings F x → S
-/
theorem to_stalk.rec_to_stalk (U HxU s)
: to_stalk.rec F x S G hg (to_stalk F x U HxU s) = G U HxU s := rfl

include HG

instance to_stalk.rec_is_ring_hom : is_ring_hom (to_stalk.rec F x S G hg) :=
{ map_one := (HG opens.univ (set.mem_univ x)).map_one ▸ rfl,
  map_add := λ y z, quotient.induction_on₂' y z $ λ ⟨U, HxU, s⟩ ⟨V, HxV, t⟩,
    begin
        have HxUV : x ∈ U ∩ V := ⟨HxU, HxV⟩,
        show G (U ∩ V) HxUV (_ + _) = G _ _ _ + G _ _ _,
        rw (HG (U ∩ V) HxUV).map_add,
        erw ←hg (U ∩ V) U (set.inter_subset_left _ _),
        erw ←hg (U ∩ V) V (set.inter_subset_right _ _),
    end,
  map_mul := λ y z, quotient.induction_on₂' y z $ λ ⟨U, HxU, s⟩ ⟨V, HxV, t⟩,
    begin
        have HxUV : x ∈ U ∩ V := ⟨HxU, HxV⟩,
        show G (U ∩ V) HxUV (_ * _) = G _ _ _ * G _ _ _,
        rw (HG (U ∩ V) HxUV).map_mul,
        erw ←hg (U ∩ V) U (set.inter_subset_left _ _),
        erw ←hg (U ∩ V) V (set.inter_subset_right _ _),
    end }

end stalk_colimit


/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
import category_theory.limits.shapes.normal_mono.basic
import category_theory.limits.shapes.finite_products

/-!
# Normal mono categories with finite products and kernels have all equalizers.

This, and the dual result, are used in the development of abelian categories.
-/

noncomputable theory

open category_theory
open category_theory.limits

variables {C : Type*} [category C] [has_zero_morphisms C]

namespace category_theory.normal_mono_category

variables [has_finite_products C] [has_kernels C] [normal_mono_category C]

/-- The pullback of two monomorphisms exists. -/
@[irreducible]
lemma pullback_of_mono {X Y Z : C} (a : X ⟶ Z) (b : Y ⟶ Z) [mono a] [mono b] :
  has_limit (cospan a b) :=
let ⟨P, f, haf, i⟩ := normal_mono_of_mono a in
let ⟨Q, g, hbg, i'⟩ := normal_mono_of_mono b in
let ⟨a', ha'⟩ := kernel_fork.is_limit.lift' i (kernel.ι (prod.lift f g)) $
    calc kernel.ι (prod.lift f g) ≫ f
        = kernel.ι (prod.lift f g) ≫ prod.lift f g ≫ limits.prod.fst : by rw prod.lift_fst
    ... = (0 : kernel (prod.lift f g) ⟶ P ⨯ Q) ≫ limits.prod.fst : by rw kernel.condition_assoc
    ... = 0 : zero_comp in
let ⟨b', hb'⟩ := kernel_fork.is_limit.lift' i' (kernel.ι (prod.lift f g)) $
    calc kernel.ι (prod.lift f g) ≫ g
        = kernel.ι (prod.lift f g) ≫ (prod.lift f g) ≫ limits.prod.snd : by rw prod.lift_snd
    ... = (0 : kernel (prod.lift f g) ⟶ P ⨯ Q) ≫ limits.prod.snd : by rw kernel.condition_assoc
    ... = 0 : zero_comp in
has_limit.mk { cone := pullback_cone.mk a' b' $ by { simp at ha' hb', rw [ha', hb'] },
  is_limit := pullback_cone.is_limit.mk _
    (λ s, kernel.lift (prod.lift f g) (pullback_cone.snd s ≫ b) $ prod.hom_ext
      (calc ((pullback_cone.snd s ≫ b) ≫ prod.lift f g) ≫ limits.prod.fst
            = pullback_cone.snd s ≫ b ≫ f : by simp only [prod.lift_fst, category.assoc]
        ... = pullback_cone.fst s ≫ a ≫ f : by rw pullback_cone.condition_assoc
        ... = pullback_cone.fst s ≫ 0 : by rw haf
        ... = 0 ≫ limits.prod.fst :
          by rw [comp_zero, zero_comp])
      (calc ((pullback_cone.snd s ≫ b) ≫ prod.lift f g) ≫ limits.prod.snd
            = pullback_cone.snd s ≫ b ≫ g : by simp only [prod.lift_snd, category.assoc]
        ... = pullback_cone.snd s ≫ 0 : by rw hbg
        ... = 0 ≫ limits.prod.snd :
          by rw [comp_zero, zero_comp]))
    (λ s, (cancel_mono a).1 $
      by { rw kernel_fork.ι_of_ι at ha', simp [ha', pullback_cone.condition s] })
    (λ s, (cancel_mono b).1 $
      by { rw kernel_fork.ι_of_ι at hb', simp [hb'] })
    (λ s m h₁ h₂, (cancel_mono (kernel.ι (prod.lift f g))).1 $ calc m ≫ kernel.ι (prod.lift f g)
          = m ≫ a' ≫ a : by { congr, exact ha'.symm }
      ... = pullback_cone.fst s ≫ a : by rw [←category.assoc, h₁]
      ... = pullback_cone.snd s ≫ b : pullback_cone.condition s
      ... = kernel.lift (prod.lift f g) (pullback_cone.snd s ≫ b) _ ≫ kernel.ι (prod.lift f g) :
        by rw kernel.lift_ι) }

section

local attribute [instance] pullback_of_mono

/-- The pullback of `(𝟙 X, f)` and `(𝟙 X, g)` -/
private abbreviation P {X Y : C} (f g : X ⟶ Y)
  [mono (prod.lift (𝟙 X) f)] [mono (prod.lift (𝟙 X) g)] : C :=
pullback (prod.lift (𝟙 X) f) (prod.lift (𝟙 X) g)

/-- The equalizer of `f` and `g` exists. -/
@[irreducible]
lemma has_limit_parallel_pair {X Y : C} (f g : X ⟶ Y) : has_limit (parallel_pair f g) :=
have huv : (pullback.fst : P f g ⟶ X) = pullback.snd, from
  calc (pullback.fst : P f g ⟶ X) = pullback.fst ≫ 𝟙 _ : eq.symm $ category.comp_id _
    ... = pullback.fst ≫ prod.lift (𝟙 X) f ≫ limits.prod.fst : by rw prod.lift_fst
    ... = pullback.snd ≫ prod.lift (𝟙 X) g ≫ limits.prod.fst : by rw pullback.condition_assoc
    ... = pullback.snd : by rw [prod.lift_fst, category.comp_id],
have hvu : (pullback.fst : P f g ⟶ X) ≫ f = pullback.snd ≫ g, from
  calc (pullback.fst : P f g ⟶ X) ≫ f
        = pullback.fst ≫ prod.lift (𝟙 X) f ≫ limits.prod.snd : by rw prod.lift_snd
    ... = pullback.snd ≫ prod.lift (𝟙 X) g ≫ limits.prod.snd : by rw pullback.condition_assoc
    ... = pullback.snd ≫ g : by rw prod.lift_snd,
have huu : (pullback.fst : P f g ⟶ X) ≫ f = pullback.fst ≫ g, by rw [hvu, ←huv],
has_limit.mk { cone := fork.of_ι pullback.fst huu,
  is_limit := fork.is_limit.mk _
  (λ s, pullback.lift (fork.ι s) (fork.ι s) $ prod.hom_ext
    (by simp only [prod.lift_fst, category.assoc])
    (by simp only [fork.app_zero_right, fork.app_zero_left, prod.lift_snd, category.assoc]))
  (λ s, by simp only [fork.ι_of_ι, pullback.lift_fst])
  (λ s m h, pullback.hom_ext
    (by simpa only [pullback.lift_fst] using h walking_parallel_pair.zero)
    (by simpa only [huv.symm, pullback.lift_fst] using h walking_parallel_pair.zero)) }

end

section
local attribute [instance] has_limit_parallel_pair

/-- A `normal_mono_category` category with finite products and kernels has all equalizers. -/
@[priority 100] instance has_equalizers : has_equalizers C :=
has_equalizers_of_has_limit_parallel_pair _

end

/-- If a zero morphism is a cokernel of `f`, then `f` is an epimorphism. -/
lemma epi_of_zero_cokernel {X Y : C} (f : X ⟶ Y) (Z : C)
  (l : is_colimit (cokernel_cofork.of_π (0 : Y ⟶ Z) (show f ≫ 0 = 0, by simp))) : epi f :=
⟨λ P u v huv,
 begin
  obtain ⟨W, w, hw, hl⟩ := normal_mono_of_mono (equalizer.ι u v),
  obtain ⟨m, hm⟩ := equalizer.lift' f huv,
  have hwf : f ≫ w = 0,
  { rw [←hm, category.assoc, hw, comp_zero] },
  obtain ⟨n, hn⟩ := cokernel_cofork.is_colimit.desc' l _ hwf,
  rw [cofork.π_of_π, zero_comp] at hn,
  haveI : is_iso (equalizer.ι u v),
  { apply is_iso_limit_cone_parallel_pair_of_eq hn.symm hl },
  apply (cancel_epi (equalizer.ι u v)).1,
  exact equalizer.condition _ _
 end⟩

section
variables [has_zero_object C]
open_locale zero_object

/-- If `f ≫ g = 0` implies `g = 0` for all `g`, then `g` is a monomorphism. -/
lemma epi_of_zero_cancel {X Y : C} (f : X ⟶ Y)
  (hf : ∀ (Z : C) (g : Y ⟶ Z) (hgf : f ≫ g = 0), g = 0) : epi f :=
epi_of_zero_cokernel f 0 $ zero_cokernel_of_zero_cancel f hf

end

end category_theory.normal_mono_category

namespace category_theory.normal_epi_category

variables [has_finite_coproducts C] [has_cokernels C] [normal_epi_category C]

/-- The pushout of two epimorphisms exists. -/
@[irreducible]
lemma pushout_of_epi {X Y Z : C} (a : X ⟶ Y) (b : X ⟶ Z) [epi a] [epi b] :
  has_colimit (span a b) :=
let ⟨P, f, hfa, i⟩ := normal_epi_of_epi a in
let ⟨Q, g, hgb, i'⟩ := normal_epi_of_epi b in
let ⟨a', ha'⟩ := cokernel_cofork.is_colimit.desc' i (cokernel.π (coprod.desc f g)) $
  calc f ≫ cokernel.π (coprod.desc f g)
      = coprod.inl ≫ coprod.desc f g ≫ cokernel.π (coprod.desc f g) : by rw coprod.inl_desc_assoc
  ... = coprod.inl ≫ (0 : P ⨿ Q ⟶ cokernel (coprod.desc f g)) : by rw cokernel.condition
  ... = 0 : has_zero_morphisms.comp_zero _ _ in
let ⟨b', hb'⟩ := cokernel_cofork.is_colimit.desc' i' (cokernel.π (coprod.desc f g)) $
  calc g ≫ cokernel.π (coprod.desc f g)
      = coprod.inr ≫ coprod.desc f g ≫ cokernel.π (coprod.desc f g) : by rw coprod.inr_desc_assoc
  ... = coprod.inr ≫ (0 : P ⨿ Q ⟶ cokernel (coprod.desc f g)) :  by rw cokernel.condition
  ... = 0 : has_zero_morphisms.comp_zero _ _ in
has_colimit.mk
{ cocone := pushout_cocone.mk a' b' $ by { simp only [cofork.π_of_π] at ha' hb', rw [ha', hb'] },
  is_colimit := pushout_cocone.is_colimit.mk _
  (λ s, cokernel.desc (coprod.desc f g) (b ≫ pushout_cocone.inr s) $ coprod.hom_ext
    (calc coprod.inl ≫ coprod.desc f g ≫ b ≫ pushout_cocone.inr s
          = f ≫ b ≫ pushout_cocone.inr s : by rw coprod.inl_desc_assoc
      ... = f ≫ a ≫ pushout_cocone.inl s : by rw pushout_cocone.condition
      ... = 0 ≫ pushout_cocone.inl s : by rw reassoc_of hfa
      ... = coprod.inl ≫ 0 : by rw [comp_zero, zero_comp])
    (calc coprod.inr ≫ coprod.desc f g ≫ b ≫ pushout_cocone.inr s
          = g ≫ b ≫ pushout_cocone.inr s : by rw coprod.inr_desc_assoc
      ... = 0 ≫ pushout_cocone.inr s : by rw reassoc_of hgb
      ... = coprod.inr ≫ 0 : by rw [comp_zero, zero_comp]))
  (λ s, (cancel_epi a).1 $
    by { rw cokernel_cofork.π_of_π at ha', simp [reassoc_of ha', pushout_cocone.condition s] })
  (λ s, (cancel_epi b).1 $ by { rw cokernel_cofork.π_of_π at hb', simp [reassoc_of hb'] })
  (λ s m h₁ h₂, (cancel_epi (cokernel.π (coprod.desc f g))).1 $
  calc cokernel.π (coprod.desc f g) ≫ m
        = (a ≫ a') ≫ m : by { congr, exact ha'.symm }
    ... = a ≫ pushout_cocone.inl s : by rw [category.assoc, h₁]
    ... = b ≫ pushout_cocone.inr s : pushout_cocone.condition s
    ... = cokernel.π (coprod.desc f g) ≫
            cokernel.desc (coprod.desc f g) (b ≫ pushout_cocone.inr s) _ :
      by rw cokernel.π_desc) }

section
local attribute [instance] pushout_of_epi

/-- The pushout of `(𝟙 Y, f)` and `(𝟙 Y, g)`. -/
private abbreviation Q {X Y : C} (f g : X ⟶ Y)
  [epi (coprod.desc (𝟙 Y) f)] [epi (coprod.desc (𝟙 Y) g)] : C :=
pushout (coprod.desc (𝟙 Y) f) (coprod.desc (𝟙 Y) g)

/-- The coequalizer of `f` and `g` exists. -/
@[irreducible]
lemma has_colimit_parallel_pair {X Y : C} (f g : X ⟶ Y) : has_colimit (parallel_pair f g) :=
have huv : (pushout.inl : Y ⟶ Q f g) = pushout.inr, from
  calc (pushout.inl : Y ⟶ Q f g) = 𝟙 _ ≫ pushout.inl : eq.symm $ category.id_comp _
    ... = (coprod.inl ≫ coprod.desc (𝟙 Y) f) ≫ pushout.inl : by rw coprod.inl_desc
    ... = (coprod.inl ≫ coprod.desc (𝟙 Y) g) ≫ pushout.inr :
      by simp only [category.assoc, pushout.condition]
    ... = pushout.inr : by rw [coprod.inl_desc, category.id_comp],
have hvu : f ≫ (pushout.inl : Y ⟶ Q f g) = g ≫ pushout.inr, from
  calc f ≫ (pushout.inl : Y ⟶ Q f g)
        = (coprod.inr ≫ coprod.desc (𝟙 Y) f) ≫ pushout.inl : by rw coprod.inr_desc
    ... = (coprod.inr ≫ coprod.desc (𝟙 Y) g) ≫ pushout.inr :
      by simp only [category.assoc, pushout.condition]
    ... = g ≫ pushout.inr : by rw coprod.inr_desc,
have huu : f ≫ (pushout.inl : Y ⟶ Q f g) = g ≫ pushout.inl, by rw [hvu, huv],
has_colimit.mk { cocone := cofork.of_π pushout.inl huu,
  is_colimit := cofork.is_colimit.mk _
  (λ s, pushout.desc (cofork.π s) (cofork.π s) $ coprod.hom_ext
    (by simp only [coprod.inl_desc_assoc])
    (by simp only [cofork.right_app_one, coprod.inr_desc_assoc, cofork.left_app_one]))
  (λ s, by simp only [pushout.inl_desc, cofork.π_of_π])
  (λ s m h, pushout.hom_ext
    (by simpa only [pushout.inl_desc] using h walking_parallel_pair.one)
    (by simpa only [huv.symm, pushout.inl_desc] using h walking_parallel_pair.one)) }

end

section
local attribute [instance] has_colimit_parallel_pair

/-- A `normal_epi_category` category with finite coproducts and cokernels has all coequalizers. -/
@[priority 100] instance has_coequalizers : has_coequalizers C :=
has_coequalizers_of_has_colimit_parallel_pair _

end

/-- If a zero morphism is a kernel of `f`, then `f` is a monomorphism. -/
lemma mono_of_zero_kernel {X Y : C} (f : X ⟶ Y) (Z : C)
  (l : is_limit (kernel_fork.of_ι (0 : Z ⟶ X) (show 0 ≫ f = 0, by simp))) : mono f :=
⟨λ P u v huv,
 begin
  obtain ⟨W, w, hw, hl⟩ := normal_epi_of_epi (coequalizer.π u v),
  obtain ⟨m, hm⟩ := coequalizer.desc' f huv,
  have hwf : w ≫ f = 0,
  { rw [←hm, reassoc_of hw, zero_comp] },
  obtain ⟨n, hn⟩ := kernel_fork.is_limit.lift' l _ hwf,
  rw [fork.ι_of_ι, has_zero_morphisms.comp_zero] at hn,
  haveI : is_iso (coequalizer.π u v),
  { apply is_iso_colimit_cocone_parallel_pair_of_eq hn.symm hl },
  apply (cancel_mono (coequalizer.π u v)).1,
  exact coequalizer.condition _ _
 end⟩

section
variables [has_zero_object C]
open_locale zero_object

/-- If `g ≫ f = 0` implies `g = 0` for all `g`, then `f` is a monomorphism. -/
lemma mono_of_cancel_zero {X Y : C} (f : X ⟶ Y)
  (hf : ∀ (Z : C) (g : Z ⟶ X) (hgf : g ≫ f = 0), g = 0) : mono f :=
mono_of_zero_kernel f 0 $ zero_kernel_of_cancel_zero f hf

end

end category_theory.normal_epi_category