/-
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Kenny Lau
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.mv_polynomial.default
import Mathlib.ring_theory.ideal.operations
import Mathlib.ring_theory.multiplicity
import Mathlib.ring_theory.algebra_tower
import Mathlib.tactic.linarith.default
import Mathlib.PostPort

universes u_1 u_2 u_3 u_4

namespace Mathlib

/-!
# Formal power series

This file defines (multivariate) formal power series
and develops the basic properties of these objects.

A formal power series is to a polynomial like an infinite sum is to a finite sum.

We provide the natural inclusion from polynomials to formal power series.

## Generalities

The file starts with setting up the (semi)ring structure on multivariate power series.

`trunc n φ` truncates a formal power series to the polynomial
that has the same coefficients as `φ`, for all `m ≤ n`, and `0` otherwise.

If the constant coefficient of a formal power series is invertible,
then this formal power series is invertible.

Formal power series over a local ring form a local ring.

## Formal power series in one variable

We prove that if the ring of coefficients is an integral domain,
then formal power series in one variable form an integral domain.

The `order` of a formal power series `φ` is the multiplicity of the variable `X` in `φ`.

If the coefficients form an integral domain, then `order` is a valuation
(`order_mul`, `le_order_add`).

## Implementation notes

In this file we define multivariate formal power series with
variables indexed by `σ` and coefficients in `R` as
`mv_power_series σ R := (σ →₀ ℕ) → R`.
Unfortunately there is not yet enough API to show that they are the completion
of the ring of multivariate polynomials. However, we provide most of the infrastructure
that is needed to do this. Once I-adic completion (topological or algebraic) is available
it should not be hard to fill in the details.

Formal power series in one variable are defined as
`power_series R := mv_power_series unit R`.

This allows us to port a lot of proofs and properties
from the multivariate case to the single variable case.
However, it means that formal power series are indexed by `unit →₀ ℕ`,
which is of course canonically isomorphic to `ℕ`.
We then build some glue to treat formal power series as if they are indexed by `ℕ`.
Occasionally this leads to proofs that are uglier than expected.
-/

/-- Multivariate formal power series, where `σ` is the index set of the variables
and `R` is the coefficient ring.-/
def mv_power_series (σ : Type u_1) (R : Type u_2) := (σ →₀ ℕ) → R

namespace mv_power_series

protected instance inhabited {σ : Type u_1} {R : Type u_2} [Inhabited R] :
    Inhabited (mv_power_series σ R) :=
  { default := fun (_x : σ →₀ ℕ) => Inhabited.default }

protected instance has_zero {σ : Type u_1} {R : Type u_2} [HasZero R] :
    HasZero (mv_power_series σ R) :=
  pi.has_zero

protected instance add_monoid {σ : Type u_1} {R : Type u_2} [add_monoid R] :
    add_monoid (mv_power_series σ R) :=
  pi.add_monoid

protected instance add_group {σ : Type u_1} {R : Type u_2} [add_group R] :
    add_group (mv_power_series σ R) :=
  pi.add_group

protected instance add_comm_monoid {σ : Type u_1} {R : Type u_2} [add_comm_monoid R] :
    add_comm_monoid (mv_power_series σ R) :=
  pi.add_comm_monoid

protected instance add_comm_group {σ : Type u_1} {R : Type u_2} [add_comm_group R] :
    add_comm_group (mv_power_series σ R) :=
  pi.add_comm_group

protected instance nontrivial {σ : Type u_1} {R : Type u_2} [nontrivial R] :
    nontrivial (mv_power_series σ R) :=
  function.nontrivial

protected instance semimodule {σ : Type u_1} {R : Type u_2} {A : Type u_3} [semiring R]
    [add_comm_monoid A] [semimodule R A] : semimodule R (mv_power_series σ A) :=
  pi.semimodule (σ →₀ ℕ) (fun (ᾰ : σ →₀ ℕ) => A) R

protected instance is_scalar_tower {σ : Type u_1} {R : Type u_2} {A : Type u_3} {S : Type u_4}
    [semiring R] [semiring S] [add_comm_monoid A] [semimodule R A] [semimodule S A] [has_scalar R S]
    [is_scalar_tower R S A] : is_scalar_tower R S (mv_power_series σ A) :=
  pi.is_scalar_tower

/-- The `n`th monomial with coefficient `a` as multivariate formal power series.-/
def monomial {σ : Type u_1} (R : Type u_2) [semiring R] (n : σ →₀ ℕ) :
    linear_map R R (mv_power_series σ R) :=
  linear_map.std_basis R (fun (n : σ →₀ ℕ) => R) n

/-- The `n`th coefficient of a multivariate formal power series.-/
def coeff {σ : Type u_1} (R : Type u_2) [semiring R] (n : σ →₀ ℕ) :
    linear_map R (mv_power_series σ R) R :=
  linear_map.proj n

/-- Two multivariate formal power series are equal if all their coefficients are equal.-/
theorem ext {σ : Type u_1} {R : Type u_2} [semiring R] {φ : mv_power_series σ R}
    {ψ : mv_power_series σ R} (h : ∀ (n : σ →₀ ℕ), coe_fn (coeff R n) φ = coe_fn (coeff R n) ψ) :
    φ = ψ :=
  funext h

/-- Two multivariate formal power series are equal
 if and only if all their coefficients are equal.-/
theorem ext_iff {σ : Type u_1} {R : Type u_2} [semiring R] {φ : mv_power_series σ R}
    {ψ : mv_power_series σ R} :
    φ = ψ ↔ ∀ (n : σ →₀ ℕ), coe_fn (coeff R n) φ = coe_fn (coeff R n) ψ :=
  function.funext_iff

theorem coeff_monomial {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (n : σ →₀ ℕ)
    (a : R) : coe_fn (coeff R m) (coe_fn (monomial R n) a) = ite (m = n) a 0 :=
  sorry

@[simp] theorem coeff_monomial_same {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ)
    (a : R) : coe_fn (coeff R n) (coe_fn (monomial R n) a) = a :=
  linear_map.std_basis_same R (fun (n : σ →₀ ℕ) => R) n a

theorem coeff_monomial_ne {σ : Type u_1} {R : Type u_2} [semiring R] {m : σ →₀ ℕ} {n : σ →₀ ℕ}
    (h : m ≠ n) (a : R) : coe_fn (coeff R m) (coe_fn (monomial R n) a) = 0 :=
  linear_map.std_basis_ne R (fun (n : σ →₀ ℕ) => R) n m h a

theorem eq_of_coeff_monomial_ne_zero {σ : Type u_1} {R : Type u_2} [semiring R] {m : σ →₀ ℕ}
    {n : σ →₀ ℕ} {a : R} (h : coe_fn (coeff R m) (coe_fn (monomial R n) a) ≠ 0) : m = n :=
  by_contra fun (h' : ¬m = n) => h (coeff_monomial_ne h' a)

@[simp] theorem coeff_comp_monomial {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ) :
    linear_map.comp (coeff R n) (monomial R n) = linear_map.id :=
  linear_map.ext (coeff_monomial_same n)

@[simp] theorem coeff_zero {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ) :
    coe_fn (coeff R n) 0 = 0 :=
  rfl

protected instance has_one {σ : Type u_1} {R : Type u_2} [semiring R] :
    HasOne (mv_power_series σ R) :=
  { one := coe_fn (monomial R 0) 1 }

theorem coeff_one {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ) :
    coe_fn (coeff R n) 1 = ite (n = 0) 1 0 :=
  coeff_monomial n 0 1

theorem coeff_zero_one {σ : Type u_1} {R : Type u_2} [semiring R] : coe_fn (coeff R 0) 1 = 1 :=
  coeff_monomial_same 0 1

theorem monomial_zero_one {σ : Type u_1} {R : Type u_2} [semiring R] :
    coe_fn (monomial R 0) 1 = 1 :=
  rfl

protected instance has_mul {σ : Type u_1} {R : Type u_2} [semiring R] : Mul (mv_power_series σ R) :=
  { mul :=
      fun (φ ψ : mv_power_series σ R) (n : σ →₀ ℕ) =>
        finset.sum (finsupp.support (finsupp.antidiagonal n))
          fun (p : (σ →₀ ℕ) × (σ →₀ ℕ)) =>
            coe_fn (coeff R (prod.fst p)) φ * coe_fn (coeff R (prod.snd p)) ψ }

theorem coeff_mul {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ) (φ : mv_power_series σ R)
    (ψ : mv_power_series σ R) :
    coe_fn (coeff R n) (φ * ψ) =
        finset.sum (finsupp.support (finsupp.antidiagonal n))
          fun (p : (σ →₀ ℕ) × (σ →₀ ℕ)) =>
            coe_fn (coeff R (prod.fst p)) φ * coe_fn (coeff R (prod.snd p)) ψ :=
  rfl

protected theorem zero_mul {σ : Type u_1} {R : Type u_2} [semiring R] (φ : mv_power_series σ R) :
    0 * φ = 0 :=
  sorry

protected theorem mul_zero {σ : Type u_1} {R : Type u_2} [semiring R] (φ : mv_power_series σ R) :
    φ * 0 = 0 :=
  sorry

theorem coeff_monomial_mul {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (a : R) :
    coe_fn (coeff R m) (coe_fn (monomial R n) a * φ) =
        ite (n ≤ m) (a * coe_fn (coeff R (m - n)) φ) 0 :=
  sorry

theorem coeff_mul_monomial {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (a : R) :
    coe_fn (coeff R m) (φ * coe_fn (monomial R n) a) =
        ite (n ≤ m) (coe_fn (coeff R (m - n)) φ * a) 0 :=
  sorry

theorem coeff_add_monomial_mul {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (a : R) :
    coe_fn (coeff R (m + n)) (coe_fn (monomial R m) a * φ) = a * coe_fn (coeff R n) φ :=
  sorry

theorem coeff_add_mul_monomial {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (a : R) :
    coe_fn (coeff R (m + n)) (φ * coe_fn (monomial R n) a) = coe_fn (coeff R m) φ * a :=
  sorry

protected theorem one_mul {σ : Type u_1} {R : Type u_2} [semiring R] (φ : mv_power_series σ R) :
    1 * φ = φ :=
  sorry

protected theorem mul_one {σ : Type u_1} {R : Type u_2} [semiring R] (φ : mv_power_series σ R) :
    φ * 1 = φ :=
  sorry

protected theorem mul_add {σ : Type u_1} {R : Type u_2} [semiring R] (φ₁ : mv_power_series σ R)
    (φ₂ : mv_power_series σ R) (φ₃ : mv_power_series σ R) : φ₁ * (φ₂ + φ₃) = φ₁ * φ₂ + φ₁ * φ₃ :=
  sorry

protected theorem add_mul {σ : Type u_1} {R : Type u_2} [semiring R] (φ₁ : mv_power_series σ R)
    (φ₂ : mv_power_series σ R) (φ₃ : mv_power_series σ R) : (φ₁ + φ₂) * φ₃ = φ₁ * φ₃ + φ₂ * φ₃ :=
  sorry

protected theorem mul_assoc {σ : Type u_1} {R : Type u_2} [semiring R] (φ₁ : mv_power_series σ R)
    (φ₂ : mv_power_series σ R) (φ₃ : mv_power_series σ R) : φ₁ * φ₂ * φ₃ = φ₁ * (φ₂ * φ₃) :=
  sorry

protected instance semiring {σ : Type u_1} {R : Type u_2} [semiring R] :
    semiring (mv_power_series σ R) :=
  semiring.mk add_comm_monoid.add sorry add_comm_monoid.zero sorry sorry sorry Mul.mul
    mv_power_series.mul_assoc 1 mv_power_series.one_mul mv_power_series.mul_one
    mv_power_series.zero_mul mv_power_series.mul_zero mv_power_series.mul_add
    mv_power_series.add_mul

protected instance comm_semiring {σ : Type u_1} {R : Type u_2} [comm_semiring R] :
    comm_semiring (mv_power_series σ R) :=
  comm_semiring.mk semiring.add sorry semiring.zero sorry sorry sorry semiring.mul sorry
    semiring.one sorry sorry sorry sorry sorry sorry sorry

protected instance ring {σ : Type u_1} {R : Type u_2} [ring R] : ring (mv_power_series σ R) :=
  ring.mk semiring.add sorry semiring.zero sorry sorry add_comm_group.neg add_comm_group.sub sorry
    sorry semiring.mul sorry semiring.one sorry sorry sorry sorry

protected instance comm_ring {σ : Type u_1} {R : Type u_2} [comm_ring R] :
    comm_ring (mv_power_series σ R) :=
  comm_ring.mk comm_semiring.add sorry comm_semiring.zero sorry sorry add_comm_group.neg
    add_comm_group.sub sorry sorry comm_semiring.mul sorry comm_semiring.one sorry sorry sorry sorry
    sorry

theorem monomial_mul_monomial {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (n : σ →₀ ℕ)
    (a : R) (b : R) :
    coe_fn (monomial R m) a * coe_fn (monomial R n) b = coe_fn (monomial R (m + n)) (a * b) :=
  sorry

/-- The constant multivariate formal power series.-/
def C (σ : Type u_1) (R : Type u_2) [semiring R] : R →+* mv_power_series σ R :=
  ring_hom.mk (linear_map.to_fun (monomial R 0)) sorry sorry sorry sorry

@[simp] theorem monomial_zero_eq_C {σ : Type u_1} {R : Type u_2} [semiring R] :
    ⇑(monomial R 0) = ⇑(C σ R) :=
  rfl

theorem monomial_zero_eq_C_apply {σ : Type u_1} {R : Type u_2} [semiring R] (a : R) :
    coe_fn (monomial R 0) a = coe_fn (C σ R) a :=
  rfl

theorem coeff_C {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ) (a : R) :
    coe_fn (coeff R n) (coe_fn (C σ R) a) = ite (n = 0) a 0 :=
  coeff_monomial n 0 a

theorem coeff_zero_C {σ : Type u_1} {R : Type u_2} [semiring R] (a : R) :
    coe_fn (coeff R 0) (coe_fn (C σ R) a) = a :=
  coeff_monomial_same 0 a

/-- The variables of the multivariate formal power series ring.-/
def X {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) : mv_power_series σ R :=
  coe_fn (monomial R (finsupp.single s 1)) 1

theorem coeff_X {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ) (s : σ) :
    coe_fn (coeff R n) (X s) = ite (n = finsupp.single s 1) 1 0 :=
  coeff_monomial n (finsupp.single s 1) 1

theorem coeff_index_single_X {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) (t : σ) :
    coe_fn (coeff R (finsupp.single t 1)) (X s) = ite (t = s) 1 0 :=
  sorry

@[simp] theorem coeff_index_single_self_X {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) :
    coe_fn (coeff R (finsupp.single s 1)) (X s) = 1 :=
  coeff_monomial_same (finsupp.single s 1) 1

theorem coeff_zero_X {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) :
    coe_fn (coeff R 0) (X s) = 0 :=
  sorry

theorem X_def {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) :
    X s = coe_fn (monomial R (finsupp.single s 1)) 1 :=
  rfl

theorem X_pow_eq {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) (n : ℕ) :
    X s ^ n = coe_fn (monomial R (finsupp.single s n)) 1 :=
  sorry

theorem coeff_X_pow {σ : Type u_1} {R : Type u_2} [semiring R] (m : σ →₀ ℕ) (s : σ) (n : ℕ) :
    coe_fn (coeff R m) (X s ^ n) = ite (m = finsupp.single s n) 1 0 :=
  sorry

@[simp] theorem coeff_mul_C {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (a : R) :
    coe_fn (coeff R n) (φ * coe_fn (C σ R) a) = coe_fn (coeff R n) φ * a :=
  sorry

@[simp] theorem coeff_C_mul {σ : Type u_1} {R : Type u_2} [semiring R] (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (a : R) :
    coe_fn (coeff R n) (coe_fn (C σ R) a * φ) = a * coe_fn (coeff R n) φ :=
  sorry

theorem coeff_zero_mul_X {σ : Type u_1} {R : Type u_2} [semiring R] (φ : mv_power_series σ R)
    (s : σ) : coe_fn (coeff R 0) (φ * X s) = 0 :=
  sorry

/-- The constant coefficient of a formal power series.-/
def constant_coeff (σ : Type u_1) (R : Type u_2) [semiring R] : mv_power_series σ R →+* R :=
  ring_hom.mk (⇑(coeff R 0)) coeff_zero_one sorry sorry sorry

@[simp] theorem coeff_zero_eq_constant_coeff {σ : Type u_1} {R : Type u_2} [semiring R] :
    ⇑(coeff R 0) = ⇑(constant_coeff σ R) :=
  rfl

theorem coeff_zero_eq_constant_coeff_apply {σ : Type u_1} {R : Type u_2} [semiring R]
    (φ : mv_power_series σ R) : coe_fn (coeff R 0) φ = coe_fn (constant_coeff σ R) φ :=
  rfl

@[simp] theorem constant_coeff_C {σ : Type u_1} {R : Type u_2} [semiring R] (a : R) :
    coe_fn (constant_coeff σ R) (coe_fn (C σ R) a) = a :=
  rfl

@[simp] theorem constant_coeff_comp_C {σ : Type u_1} {R : Type u_2} [semiring R] :
    ring_hom.comp (constant_coeff σ R) (C σ R) = ring_hom.id R :=
  rfl

@[simp] theorem constant_coeff_zero {σ : Type u_1} {R : Type u_2} [semiring R] :
    coe_fn (constant_coeff σ R) 0 = 0 :=
  rfl

@[simp] theorem constant_coeff_one {σ : Type u_1} {R : Type u_2} [semiring R] :
    coe_fn (constant_coeff σ R) 1 = 1 :=
  rfl

@[simp] theorem constant_coeff_X {σ : Type u_1} {R : Type u_2} [semiring R] (s : σ) :
    coe_fn (constant_coeff σ R) (X s) = 0 :=
  coeff_zero_X s

/-- If a multivariate formal power series is invertible,
 then so is its constant coefficient.-/
theorem is_unit_constant_coeff {σ : Type u_1} {R : Type u_2} [semiring R] (φ : mv_power_series σ R)
    (h : is_unit φ) : is_unit (coe_fn (constant_coeff σ R) φ) :=
  is_unit.map' (⇑(constant_coeff σ R)) h

@[simp] theorem coeff_smul {σ : Type u_1} {R : Type u_2} [semiring R] (f : mv_power_series σ R)
    (n : σ →₀ ℕ) (a : R) : coe_fn (coeff R n) (a • f) = a * coe_fn (coeff R n) f :=
  rfl

theorem X_inj {σ : Type u_1} {R : Type u_2} [semiring R] [nontrivial R] {s : σ} {t : σ} :
    X s = X t ↔ s = t :=
  sorry

/-- The map between multivariate formal power series induced by a map on the coefficients.-/
def map (σ : Type u_1) {R : Type u_2} {S : Type u_3} [semiring R] [semiring S] (f : R →+* S) :
    mv_power_series σ R →+* mv_power_series σ S :=
  ring_hom.mk (fun (φ : mv_power_series σ R) (n : σ →₀ ℕ) => coe_fn f (coe_fn (coeff R n) φ)) sorry
    sorry sorry sorry

@[simp] theorem map_id {σ : Type u_1} {R : Type u_2} [semiring R] :
    map σ (ring_hom.id R) = ring_hom.id (mv_power_series σ R) :=
  rfl

theorem map_comp {σ : Type u_1} {R : Type u_2} {S : Type u_3} {T : Type u_4} [semiring R]
    [semiring S] [semiring T] (f : R →+* S) (g : S →+* T) :
    map σ (ring_hom.comp g f) = ring_hom.comp (map σ g) (map σ f) :=
  rfl

@[simp] theorem coeff_map {σ : Type u_1} {R : Type u_2} {S : Type u_3} [semiring R] [semiring S]
    (f : R →+* S) (n : σ →₀ ℕ) (φ : mv_power_series σ R) :
    coe_fn (coeff S n) (coe_fn (map σ f) φ) = coe_fn f (coe_fn (coeff R n) φ) :=
  rfl

@[simp] theorem constant_coeff_map {σ : Type u_1} {R : Type u_2} {S : Type u_3} [semiring R]
    [semiring S] (f : R →+* S) (φ : mv_power_series σ R) :
    coe_fn (constant_coeff σ S) (coe_fn (map σ f) φ) = coe_fn f (coe_fn (constant_coeff σ R) φ) :=
  rfl

@[simp] theorem map_monomial {σ : Type u_1} {R : Type u_2} {S : Type u_3} [semiring R] [semiring S]
    (f : R →+* S) (n : σ →₀ ℕ) (a : R) :
    coe_fn (map σ f) (coe_fn (monomial R n) a) = coe_fn (monomial S n) (coe_fn f a) :=
  sorry

@[simp] theorem map_C {σ : Type u_1} {R : Type u_2} {S : Type u_3} [semiring R] [semiring S]
    (f : R →+* S) (a : R) : coe_fn (map σ f) (coe_fn (C σ R) a) = coe_fn (C σ S) (coe_fn f a) :=
  map_monomial f 0 a

@[simp] theorem map_X {σ : Type u_1} {R : Type u_2} {S : Type u_3} [semiring R] [semiring S]
    (f : R →+* S) (s : σ) : coe_fn (map σ f) (X s) = X s :=
  sorry

protected instance algebra {σ : Type u_1} {R : Type u_2} {A : Type u_3} [comm_semiring R]
    [semiring A] [algebra R A] : algebra R (mv_power_series σ A) :=
  algebra.mk (ring_hom.comp (map σ (algebra_map R A)) (C σ R)) sorry sorry

/-- Auxiliary definition for the truncation function. -/
def trunc_fun {σ : Type u_1} {R : Type u_2} [comm_semiring R] (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) : mv_polynomial σ R :=
  finsupp.mk
    (finset.filter (fun (m : σ →₀ ℕ) => coe_fn (coeff R m) φ ≠ 0)
      (finset.image prod.fst (finsupp.support (finsupp.antidiagonal n))))
    (fun (m : σ →₀ ℕ) => ite (m ≤ n) (coe_fn (coeff R m) φ) 0) sorry

/-- The `n`th truncation of a multivariate formal power series to a multivariate polynomial -/
def trunc {σ : Type u_1} (R : Type u_2) [comm_semiring R] (n : σ →₀ ℕ) :
    mv_power_series σ R →+ mv_polynomial σ R :=
  add_monoid_hom.mk (trunc_fun n) sorry sorry

theorem coeff_trunc {σ : Type u_1} {R : Type u_2} [comm_semiring R] (n : σ →₀ ℕ) (m : σ →₀ ℕ)
    (φ : mv_power_series σ R) :
    mv_polynomial.coeff m (coe_fn (trunc R n) φ) = ite (m ≤ n) (coe_fn (coeff R m) φ) 0 :=
  rfl

@[simp] theorem trunc_one {σ : Type u_1} {R : Type u_2} [comm_semiring R] (n : σ →₀ ℕ) :
    coe_fn (trunc R n) 1 = 1 :=
  sorry

@[simp] theorem trunc_C {σ : Type u_1} {R : Type u_2} [comm_semiring R] (n : σ →₀ ℕ) (a : R) :
    coe_fn (trunc R n) (coe_fn (C σ R) a) = coe_fn mv_polynomial.C a :=
  sorry

theorem X_pow_dvd_iff {σ : Type u_1} {R : Type u_2} [comm_semiring R] {s : σ} {n : ℕ}
    {φ : mv_power_series σ R} :
    X s ^ n ∣ φ ↔ ∀ (m : σ →₀ ℕ), coe_fn m s < n → coe_fn (coeff R m) φ = 0 :=
  sorry

theorem X_dvd_iff {σ : Type u_1} {R : Type u_2} [comm_semiring R] {s : σ}
    {φ : mv_power_series σ R} :
    X s ∣ φ ↔ ∀ (m : σ →₀ ℕ), coe_fn m s = 0 → coe_fn (coeff R m) φ = 0 :=
  sorry

/-
The inverse of a multivariate formal power series is defined by
well-founded recursion on the coeffients of the inverse.
-/

/-- Auxiliary definition that unifies
 the totalised inverse formal power series `(_)⁻¹` and
 the inverse formal power series that depends on
 an inverse of the constant coefficient `inv_of_unit`.-/
protected def inv.aux {σ : Type u_1} {R : Type u_2} [ring R] (a : R) (φ : mv_power_series σ R) :
    mv_power_series σ R :=
  sorry

theorem coeff_inv_aux {σ : Type u_1} {R : Type u_2} [ring R] (n : σ →₀ ℕ) (a : R)
    (φ : mv_power_series σ R) :
    coe_fn (coeff R n) (inv.aux a φ) =
        ite (n = 0) a
          (-a *
            finset.sum (finsupp.support (finsupp.antidiagonal n))
              fun (x : (σ →₀ ℕ) × (σ →₀ ℕ)) =>
                ite (prod.snd x < n)
                  (coe_fn (coeff R (prod.fst x)) φ * coe_fn (coeff R (prod.snd x)) (inv.aux a φ))
                  0) :=
  sorry

/-- A multivariate formal power series is invertible if the constant coefficient is invertible.-/
def inv_of_unit {σ : Type u_1} {R : Type u_2} [ring R] (φ : mv_power_series σ R) (u : units R) :
    mv_power_series σ R :=
  inv.aux (↑(u⁻¹)) φ

theorem coeff_inv_of_unit {σ : Type u_1} {R : Type u_2} [ring R] (n : σ →₀ ℕ)
    (φ : mv_power_series σ R) (u : units R) :
    coe_fn (coeff R n) (inv_of_unit φ u) =
        ite (n = 0) (↑(u⁻¹))
          (-↑(u⁻¹) *
            finset.sum (finsupp.support (finsupp.antidiagonal n))
              fun (x : (σ →₀ ℕ) × (σ →₀ ℕ)) =>
                ite (prod.snd x < n)
                  (coe_fn (coeff R (prod.fst x)) φ *
                    coe_fn (coeff R (prod.snd x)) (inv_of_unit φ u))
                  0) :=
  coeff_inv_aux n (↑(u⁻¹)) φ

@[simp] theorem constant_coeff_inv_of_unit {σ : Type u_1} {R : Type u_2} [ring R]
    (φ : mv_power_series σ R) (u : units R) :
    coe_fn (constant_coeff σ R) (inv_of_unit φ u) = ↑(u⁻¹) :=
  sorry

theorem mul_inv_of_unit {σ : Type u_1} {R : Type u_2} [ring R] (φ : mv_power_series σ R)
    (u : units R) (h : coe_fn (constant_coeff σ R) φ = ↑u) : φ * inv_of_unit φ u = 1 :=
  sorry

/-- Multivariate formal power series over a local ring form a local ring. -/
protected instance is_local_ring {σ : Type u_1} {R : Type u_2} [comm_ring R] [local_ring R] :
    local_ring (mv_power_series σ R) :=
  sorry

-- TODO(jmc): once adic topology lands, show that this is complete

-- Thanks to the linter for informing us that  this instance does

-- not actually need R and S to be local rings!

/-- The map `A[[X]] → B[[X]]` induced by a local ring hom `A → B` is local -/
protected instance map.is_local_ring_hom {σ : Type u_1} {R : Type u_2} {S : Type u_3} [comm_ring R]
    [comm_ring S] (f : R →+* S) [is_local_ring_hom f] : is_local_ring_hom (map σ f) :=
  is_local_ring_hom.mk
    fun (φ : mv_power_series σ R) (ᾰ : is_unit (coe_fn (map σ f) φ)) =>
      Exists.dcases_on ᾰ
        fun (ψ : units (mv_power_series σ S)) (h : ↑ψ = coe_fn (map σ f) φ) =>
          Exists.dcases_on
            (is_unit_of_map_unit f (coe_fn (constant_coeff σ R) φ)
              (eq.mp
                (Eq._oldrec (Eq.refl (is_unit (coe_fn (constant_coeff σ S) ↑ψ)))
                  (eq.mp
                    (Eq._oldrec
                      (Eq.refl
                        (coe_fn (constant_coeff σ S) ↑ψ =
                          coe_fn (constant_coeff σ S) (coe_fn (map σ f) φ)))
                      (constant_coeff_map f φ))
                    (congr_arg (⇑(constant_coeff σ S)) h)))
                (is_unit_constant_coeff (↑ψ) (is_unit_unit ψ))))
            fun (c : units R) (hc : ↑c = coe_fn (constant_coeff σ R) φ) =>
              is_unit_of_mul_eq_one φ (inv_of_unit φ c) (mul_inv_of_unit φ c (Eq.symm hc))

protected instance local_ring {σ : Type u_1} {R : Type u_2} [comm_ring R] [local_ring R] :
    local_ring (mv_power_series σ R) :=
  local_ring.mk local_ring.is_local

/-- The inverse `1/f` of a multivariable power series `f` over a field -/
protected def inv {σ : Type u_1} {k : Type u_3} [field k] (φ : mv_power_series σ k) :
    mv_power_series σ k :=
  sorry

protected instance has_inv {σ : Type u_1} {k : Type u_3} [field k] :
    has_inv (mv_power_series σ k) :=
  has_inv.mk mv_power_series.inv

theorem coeff_inv {σ : Type u_1} {k : Type u_3} [field k] (n : σ →₀ ℕ) (φ : mv_power_series σ k) :
    coe_fn (coeff k n) (φ⁻¹) =
        ite (n = 0) (coe_fn (constant_coeff σ k) φ⁻¹)
          (-(coe_fn (constant_coeff σ k) φ⁻¹) *
            finset.sum (finsupp.support (finsupp.antidiagonal n))
              fun (x : (σ →₀ ℕ) × (σ →₀ ℕ)) =>
                ite (prod.snd x < n)
                  (coe_fn (coeff k (prod.fst x)) φ * coe_fn (coeff k (prod.snd x)) (φ⁻¹)) 0) :=
  coeff_inv_aux n (coe_fn (constant_coeff σ k) φ⁻¹) φ

@[simp] theorem constant_coeff_inv {σ : Type u_1} {k : Type u_3} [field k]
    (φ : mv_power_series σ k) :
    coe_fn (constant_coeff σ k) (φ⁻¹) = (coe_fn (constant_coeff σ k) φ⁻¹) :=
  sorry

theorem inv_eq_zero {σ : Type u_1} {k : Type u_3} [field k] {φ : mv_power_series σ k} :
    φ⁻¹ = 0 ↔ coe_fn (constant_coeff σ k) φ = 0 :=
  sorry

@[simp] theorem inv_of_unit_eq {σ : Type u_1} {k : Type u_3} [field k] (φ : mv_power_series σ k)
    (h : coe_fn (constant_coeff σ k) φ ≠ 0) :
    inv_of_unit φ (units.mk0 (coe_fn (constant_coeff σ k) φ) h) = (φ⁻¹) :=
  rfl

@[simp] theorem inv_of_unit_eq' {σ : Type u_1} {k : Type u_3} [field k] (φ : mv_power_series σ k)
    (u : units k) (h : coe_fn (constant_coeff σ k) φ = ↑u) : inv_of_unit φ u = (φ⁻¹) :=
  sorry

@[simp] protected theorem mul_inv {σ : Type u_1} {k : Type u_3} [field k] (φ : mv_power_series σ k)
    (h : coe_fn (constant_coeff σ k) φ ≠ 0) : φ * (φ⁻¹) = 1 :=
  sorry

@[simp] protected theorem inv_mul {σ : Type u_1} {k : Type u_3} [field k] (φ : mv_power_series σ k)
    (h : coe_fn (constant_coeff σ k) φ ≠ 0) : φ⁻¹ * φ = 1 :=
  eq.mpr (id (Eq._oldrec (Eq.refl (φ⁻¹ * φ = 1)) (mul_comm (φ⁻¹) φ)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (φ * (φ⁻¹) = 1)) (mv_power_series.mul_inv φ h))) (Eq.refl 1))

protected theorem eq_mul_inv_iff_mul_eq {σ : Type u_1} {k : Type u_3} [field k]
    {φ₁ : mv_power_series σ k} {φ₂ : mv_power_series σ k} {φ₃ : mv_power_series σ k}
    (h : coe_fn (constant_coeff σ k) φ₃ ≠ 0) : φ₁ = φ₂ * (φ₃⁻¹) ↔ φ₁ * φ₃ = φ₂ :=
  sorry

protected theorem eq_inv_iff_mul_eq_one {σ : Type u_1} {k : Type u_3} [field k]
    {φ : mv_power_series σ k} {ψ : mv_power_series σ k} (h : coe_fn (constant_coeff σ k) ψ ≠ 0) :
    φ = (ψ⁻¹) ↔ φ * ψ = 1 :=
  eq.mpr
    (id
      (Eq._oldrec (Eq.refl (φ = (ψ⁻¹) ↔ φ * ψ = 1))
        (Eq.symm (propext (mv_power_series.eq_mul_inv_iff_mul_eq h)))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (φ = (ψ⁻¹) ↔ φ = 1 * (ψ⁻¹))) (one_mul (ψ⁻¹))))
      (iff.refl (φ = (ψ⁻¹))))

protected theorem inv_eq_iff_mul_eq_one {σ : Type u_1} {k : Type u_3} [field k]
    {φ : mv_power_series σ k} {ψ : mv_power_series σ k} (h : coe_fn (constant_coeff σ k) ψ ≠ 0) :
    ψ⁻¹ = φ ↔ φ * ψ = 1 :=
  eq.mpr (id (Eq._oldrec (Eq.refl (ψ⁻¹ = φ ↔ φ * ψ = 1)) (propext eq_comm)))
    (eq.mpr
      (id
        (Eq._oldrec (Eq.refl (φ = (ψ⁻¹) ↔ φ * ψ = 1))
          (propext (mv_power_series.eq_inv_iff_mul_eq_one h))))
      (iff.refl (φ * ψ = 1)))

end mv_power_series

namespace mv_polynomial

/-- The natural inclusion from multivariate polynomials into multivariate formal power series.-/
protected instance coe_to_mv_power_series {σ : Type u_1} {R : Type u_2} [comm_semiring R] :
    has_coe (mv_polynomial σ R) (mv_power_series σ R) :=
  has_coe.mk fun (φ : mv_polynomial σ R) (n : σ →₀ ℕ) => coeff n φ

@[simp] theorem coeff_coe {σ : Type u_1} {R : Type u_2} [comm_semiring R] (φ : mv_polynomial σ R)
    (n : σ →₀ ℕ) : coe_fn (mv_power_series.coeff R n) ↑φ = coeff n φ :=
  rfl

@[simp] theorem coe_monomial {σ : Type u_1} {R : Type u_2} [comm_semiring R] (n : σ →₀ ℕ) (a : R) :
    ↑(monomial n a) = coe_fn (mv_power_series.monomial R n) a :=
  sorry

@[simp] theorem coe_zero {σ : Type u_1} {R : Type u_2} [comm_semiring R] : ↑0 = 0 := rfl

@[simp] theorem coe_one {σ : Type u_1} {R : Type u_2} [comm_semiring R] : ↑1 = 1 := coe_monomial 0 1

@[simp] theorem coe_add {σ : Type u_1} {R : Type u_2} [comm_semiring R] (φ : mv_polynomial σ R)
    (ψ : mv_polynomial σ R) : ↑(φ + ψ) = ↑φ + ↑ψ :=
  rfl

@[simp] theorem coe_mul {σ : Type u_1} {R : Type u_2} [comm_semiring R] (φ : mv_polynomial σ R)
    (ψ : mv_polynomial σ R) : ↑(φ * ψ) = ↑φ * ↑ψ :=
  sorry

@[simp] theorem coe_C {σ : Type u_1} {R : Type u_2} [comm_semiring R] (a : R) :
    ↑(coe_fn C a) = coe_fn (mv_power_series.C σ R) a :=
  coe_monomial 0 a

@[simp] theorem coe_X {σ : Type u_1} {R : Type u_2} [comm_semiring R] (s : σ) :
    ↑(X s) = mv_power_series.X s :=
  coe_monomial (finsupp.single s 1) 1

/--
The coercion from multivariable polynomials to multivariable power series
as a ring homomorphism.
-/
-- TODO as an algebra homomorphism?

def coe_to_mv_power_series.ring_hom {σ : Type u_1} {R : Type u_2} [comm_semiring R] :
    mv_polynomial σ R →+* mv_power_series σ R :=
  ring_hom.mk coe coe_one coe_mul coe_zero coe_add

end mv_polynomial

/-- Formal power series over the coefficient ring `R`.-/
def power_series (R : Type u_1) := mv_power_series Unit R

namespace power_series

protected instance inhabited {R : Type u_1} [Inhabited R] : Inhabited (power_series R) :=
  mv_power_series.inhabited

protected instance add_monoid {R : Type u_1} [add_monoid R] : add_monoid (power_series R) :=
  mv_power_series.add_monoid

protected instance add_group {R : Type u_1} [add_group R] : add_group (power_series R) :=
  mv_power_series.add_group

protected instance add_comm_monoid {R : Type u_1} [add_comm_monoid R] :
    add_comm_monoid (power_series R) :=
  mv_power_series.add_comm_monoid

protected instance add_comm_group {R : Type u_1} [add_comm_group R] :
    add_comm_group (power_series R) :=
  mv_power_series.add_comm_group

protected instance semiring {R : Type u_1} [semiring R] : semiring (power_series R) :=
  mv_power_series.semiring

protected instance comm_semiring {R : Type u_1} [comm_semiring R] :
    comm_semiring (power_series R) :=
  mv_power_series.comm_semiring

protected instance ring {R : Type u_1} [ring R] : ring (power_series R) := mv_power_series.ring

protected instance comm_ring {R : Type u_1} [comm_ring R] : comm_ring (power_series R) :=
  mv_power_series.comm_ring

protected instance nontrivial {R : Type u_1} [nontrivial R] : nontrivial (power_series R) :=
  mv_power_series.nontrivial

protected instance semimodule {R : Type u_1} {A : Type u_2} [semiring R] [add_comm_monoid A]
    [semimodule R A] : semimodule R (power_series A) :=
  mv_power_series.semimodule

protected instance is_scalar_tower {R : Type u_1} {A : Type u_2} {S : Type u_3} [semiring R]
    [semiring S] [add_comm_monoid A] [semimodule R A] [semimodule S A] [has_scalar R S]
    [is_scalar_tower R S A] : is_scalar_tower R S (power_series A) :=
  pi.is_scalar_tower

protected instance algebra {R : Type u_1} [comm_ring R] : algebra R (power_series R) :=
  mv_power_series.algebra

/-- The `n`th coefficient of a formal power series.-/
def coeff (R : Type u_1) [semiring R] (n : ℕ) : linear_map R (power_series R) R :=
  mv_power_series.coeff R (finsupp.single Unit.unit n)

/-- The `n`th monomial with coefficient `a` as formal power series.-/
def monomial (R : Type u_1) [semiring R] (n : ℕ) : linear_map R R (power_series R) :=
  mv_power_series.monomial R (finsupp.single Unit.unit n)

theorem coeff_def {R : Type u_1} [semiring R] {s : Unit →₀ ℕ} {n : ℕ} (h : coe_fn s Unit.unit = n) :
    coeff R n = mv_power_series.coeff R s :=
  sorry

/-- Two formal power series are equal if all their coefficients are equal.-/
theorem ext {R : Type u_1} [semiring R] {φ : power_series R} {ψ : power_series R}
    (h : ∀ (n : ℕ), coe_fn (coeff R n) φ = coe_fn (coeff R n) ψ) : φ = ψ :=
  sorr


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

! This file was ported from Lean 3 source module linear_algebra.affine_space.pointwise
! leanprover-community/mathlib commit e96bdfbd1e8c98a09ff75f7ac6204d142debc840
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.LinearAlgebra.AffineSpace.AffineSubspace

/-! # Pointwise instances on `affine_subspace`s

This file provides the additive action `affine_subspace.pointwise_add_action` in the
`pointwise` locale.

-/

open Affine Pointwise

open Set

namespace AffineSubspace

variable {k : Type _} [Ring k]

variable {V P V₁ P₁ V₂ P₂ : Type _}

variable [AddCommGroup V] [Module k V] [affine_space V P]

variable [AddCommGroup V₁] [Module k V₁] [AddTorsor V₁ P₁]

variable [AddCommGroup V₂] [Module k V₂] [AddTorsor V₂ P₂]

include V

#print AffineSubspace.pointwiseAddAction /-
/-- The additive action on an affine subspace corresponding to applying the action to every element.

This is available as an instance in the `pointwise` locale. -/
protected def pointwiseAddAction : AddAction V (AffineSubspace k P)
    where
  vadd x S := S.map (AffineEquiv.constVAdd k P x)
  zero_vadd p := ((congr_arg fun f => p.map f) <| AffineMap.ext <| zero_vadd _).trans p.map_id
  add_vadd x y p :=
    ((congr_arg fun f => p.map f) <| AffineMap.ext <| add_vadd _ _).trans (p.map_map _ _).symm
#align affine_subspace.pointwise_add_action AffineSubspace.pointwiseAddAction
-/

scoped[Pointwise] attribute [instance] AffineSubspace.pointwiseAddAction

open Pointwise

/- warning: affine_subspace.coe_pointwise_vadd -> AffineSubspace.coe_pointwise_vadd is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_1 : Ring.{u1} k] {V : Type.{u2}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] (v : V) (s : AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4), Eq.{succ u3} (Set.{u3} P) ((fun (a : Type.{u3}) (b : Type.{u3}) [self : HasLiftT.{succ u3, succ u3} a b] => self.0) (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (Set.{u3} P) (HasLiftT.mk.{succ u3, succ u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (Set.{u3} P) (CoeTCₓ.coe.{succ u3, succ u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (Set.{u3} P) (SetLike.Set.hasCoeT.{u3, u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.setLike.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)))) (VAdd.vadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toHasVadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u1, u2, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4)) v s)) (VAdd.vadd.{u2, u3} V (Set.{u3} P) (Set.vaddSet.{u2, u3} V P (AddAction.toHasVadd.{u2, u3} V P (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AddTorsor.toAddAction.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2) _inst_4))) v ((fun (a : Type.{u3}) (b : Type.{u3}) [self : HasLiftT.{succ u3, succ u3} a b] => self.0) (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (Set.{u3} P) (HasLiftT.mk.{succ u3, succ u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (Set.{u3} P) (CoeTCₓ.coe.{succ u3, succ u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (Set.{u3} P) (SetLike.Set.hasCoeT.{u3, u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.setLike.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)))) s))
but is expected to have type
  forall {k : Type.{u3}} [_inst_1 : Ring.{u3} k] {V : Type.{u2}} {P : Type.{u1}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u3, u2} k V (Ring.toSemiring.{u3} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] (v : V) (s : AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4), Eq.{succ u1} (Set.{u1} P) (SetLike.coe.{u1, u1} (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.instSetLikeAffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (HVAdd.hVAdd.{u2, u1, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (instHVAdd.{u2, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toVAdd.{u2, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u3, u2, u1} k _inst_1 V P _inst_2 _inst_3 _inst_4))) v s)) (HVAdd.hVAdd.{u2, u1, u1} V (Set.{u1} P) (Set.{u1} P) (instHVAdd.{u2, u1} V (Set.{u1} P) (Set.vaddSet.{u2, u1} V P (AddAction.toVAdd.{u2, u1} V P (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AddTorsor.toAddAction.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_2) _inst_4)))) v (SetLike.coe.{u1, u1} (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.instSetLikeAffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) s))
Case conversion may be inaccurate. Consider using '#align affine_subspace.coe_pointwise_vadd AffineSubspace.coe_pointwise_vaddₓ'. -/
@[simp]
theorem coe_pointwise_vadd (v : V) (s : AffineSubspace k P) :
    ((v +ᵥ s : AffineSubspace k P) : Set P) = v +ᵥ s :=
  rfl
#align affine_subspace.coe_pointwise_vadd AffineSubspace.coe_pointwise_vadd

/- warning: affine_subspace.vadd_mem_pointwise_vadd_iff -> AffineSubspace.vadd_mem_pointwise_vadd_iff is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_1 : Ring.{u1} k] {V : Type.{u2}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] {v : V} {s : AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4} {p : P}, Iff (Membership.Mem.{u3, u3} P (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SetLike.hasMem.{u3, u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.setLike.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)) (VAdd.vadd.{u2, u3} V P (AddAction.toHasVadd.{u2, u3} V P (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AddTorsor.toAddAction.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2) _inst_4)) v p) (VAdd.vadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toHasVadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u1, u2, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4)) v s)) (Membership.Mem.{u3, u3} P (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SetLike.hasMem.{u3, u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.setLike.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)) p s)
but is expected to have type
  forall {k : Type.{u3}} [_inst_1 : Ring.{u3} k] {V : Type.{u2}} {P : Type.{u1}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u3, u2} k V (Ring.toSemiring.{u3} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] {v : V} {s : AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4} {p : P}, Iff (Membership.mem.{u1, u1} P (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SetLike.instMembership.{u1, u1} (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.instSetLikeAffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4)) (HVAdd.hVAdd.{u2, u1, u1} V P P (instHVAdd.{u2, u1} V P (AddAction.toVAdd.{u2, u1} V P (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AddTorsor.toAddAction.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_2) _inst_4))) v p) (HVAdd.hVAdd.{u2, u1, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (instHVAdd.{u2, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toVAdd.{u2, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u3, u2, u1} k _inst_1 V P _inst_2 _inst_3 _inst_4))) v s)) (Membership.mem.{u1, u1} P (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SetLike.instMembership.{u1, u1} (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) P (AffineSubspace.instSetLikeAffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4)) p s)
Case conversion may be inaccurate. Consider using '#align affine_subspace.vadd_mem_pointwise_vadd_iff AffineSubspace.vadd_mem_pointwise_vadd_iffₓ'. -/
theorem vadd_mem_pointwise_vadd_iff {v : V} {s : AffineSubspace k P} {p : P} :
    v +ᵥ p ∈ v +ᵥ s ↔ p ∈ s :=
  vadd_mem_vadd_set_iff
#align affine_subspace.vadd_mem_pointwise_vadd_iff AffineSubspace.vadd_mem_pointwise_vadd_iff

/- warning: affine_subspace.pointwise_vadd_bot -> AffineSubspace.pointwise_vadd_bot is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_1 : Ring.{u1} k] {V : Type.{u2}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] (v : V), Eq.{succ u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (VAdd.vadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toHasVadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u1, u2, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4)) v (Bot.bot.{u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (CompleteLattice.toHasBot.{u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.completeLattice.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)))) (Bot.bot.{u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (CompleteLattice.toHasBot.{u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.completeLattice.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)))
but is expected to have type
  forall {k : Type.{u2}} [_inst_1 : Ring.{u2} k] {V : Type.{u1}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u1} V] [_inst_3 : Module.{u2, u1} k V (Ring.toSemiring.{u2} k _inst_1) (AddCommGroup.toAddCommMonoid.{u1} V _inst_2)] [_inst_4 : AddTorsor.{u1, u3} V P (AddCommGroup.toAddGroup.{u1} V _inst_2)] (v : V), Eq.{succ u3} (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (HVAdd.hVAdd.{u1, u3, u3} V (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (instHVAdd.{u1, u3} V (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toVAdd.{u1, u3} V (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u1} V (AddGroup.toSubNegMonoid.{u1} V (AddCommGroup.toAddGroup.{u1} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u2, u1, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4))) v (Bot.bot.{u3} (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (CompleteLattice.toBot.{u3} (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.instCompleteLatticeAffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)))) (Bot.bot.{u3} (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (CompleteLattice.toBot.{u3} (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.instCompleteLatticeAffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4)))
Case conversion may be inaccurate. Consider using '#align affine_subspace.pointwise_vadd_bot AffineSubspace.pointwise_vadd_botₓ'. -/
theorem pointwise_vadd_bot (v : V) : v +ᵥ (⊥ : AffineSubspace k P) = ⊥ := by simp [SetLike.ext'_iff]
#align affine_subspace.pointwise_vadd_bot AffineSubspace.pointwise_vadd_bot

/- warning: affine_subspace.pointwise_vadd_direction -> AffineSubspace.pointwise_vadd_direction is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_1 : Ring.{u1} k] {V : Type.{u2}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] (v : V) (s : AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4), Eq.{succ u2} (Submodule.{u1, u2} k V (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2) _inst_3) (AffineSubspace.direction.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4 (VAdd.vadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toHasVadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u1, u2, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4)) v s)) (AffineSubspace.direction.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4 s)
but is expected to have type
  forall {k : Type.{u3}} [_inst_1 : Ring.{u3} k] {V : Type.{u2}} {P : Type.{u1}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u3, u2} k V (Ring.toSemiring.{u3} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] (v : V) (s : AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4), Eq.{succ u2} (Submodule.{u3, u2} k V (Ring.toSemiring.{u3} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2) _inst_3) (AffineSubspace.direction.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4 (HVAdd.hVAdd.{u2, u1, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (instHVAdd.{u2, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toVAdd.{u2, u1} V (AffineSubspace.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u3, u2, u1} k _inst_1 V P _inst_2 _inst_3 _inst_4))) v s)) (AffineSubspace.direction.{u3, u2, u1} k V P _inst_1 _inst_2 _inst_3 _inst_4 s)
Case conversion may be inaccurate. Consider using '#align affine_subspace.pointwise_vadd_direction AffineSubspace.pointwise_vadd_directionₓ'. -/
theorem pointwise_vadd_direction (v : V) (s : AffineSubspace k P) :
    (v +ᵥ s).direction = s.direction := by
  unfold VAdd.vadd
  rw [map_direction]
  exact Submodule.map_id _
#align affine_subspace.pointwise_vadd_direction AffineSubspace.pointwise_vadd_direction

/- warning: affine_subspace.pointwise_vadd_span -> AffineSubspace.pointwise_vadd_span is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_1 : Ring.{u1} k] {V : Type.{u2}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u2} V] [_inst_3 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V _inst_2)] [_inst_4 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2)] (v : V) (s : Set.{u3} P), Eq.{succ u3} (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (VAdd.vadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toHasVadd.{u2, u3} V (AffineSubspace.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u1, u2, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4)) v (affineSpan.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4 s)) (affineSpan.{u1, u2, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4 (VAdd.vadd.{u2, u3} V (Set.{u3} P) (Set.vaddSet.{u2, u3} V P (AddAction.toHasVadd.{u2, u3} V P (SubNegMonoid.toAddMonoid.{u2} V (AddGroup.toSubNegMonoid.{u2} V (AddCommGroup.toAddGroup.{u2} V _inst_2))) (AddTorsor.toAddAction.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_2) _inst_4))) v s))
but is expected to have type
  forall {k : Type.{u2}} [_inst_1 : Ring.{u2} k] {V : Type.{u1}} {P : Type.{u3}} [_inst_2 : AddCommGroup.{u1} V] [_inst_3 : Module.{u2, u1} k V (Ring.toSemiring.{u2} k _inst_1) (AddCommGroup.toAddCommMonoid.{u1} V _inst_2)] [_inst_4 : AddTorsor.{u1, u3} V P (AddCommGroup.toAddGroup.{u1} V _inst_2)] (v : V) (s : Set.{u3} P), Eq.{succ u3} (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (HVAdd.hVAdd.{u1, u3, u3} V (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (instHVAdd.{u1, u3} V (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (AddAction.toVAdd.{u1, u3} V (AffineSubspace.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4) (SubNegMonoid.toAddMonoid.{u1} V (AddGroup.toSubNegMonoid.{u1} V (AddCommGroup.toAddGroup.{u1} V _inst_2))) (AffineSubspace.pointwiseAddAction.{u2, u1, u3} k _inst_1 V P _inst_2 _inst_3 _inst_4))) v (affineSpan.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4 s)) (affineSpan.{u2, u1, u3} k V P _inst_1 _inst_2 _inst_3 _inst_4 (HVAdd.hVAdd.{u1, u3, u3} V (Set.{u3} P) (Set.{u3} P) (instHVAdd.{u1, u3} V (Set.{u3} P) (Set.vaddSet.{u1, u3} V P (AddAction.toVAdd.{u1, u3} V P (SubNegMonoid.toAddMonoid.{u1} V (AddGroup.toSubNegMonoid.{u1} V (AddCommGroup.toAddGroup.{u1} V _inst_2))) (AddTorsor.toAddAction.{u1, u3} V P (AddCommGroup.toAddGroup.{u1} V _inst_2) _inst_4)))) v s))
Case conversion may be inaccurate. Consider using '#align affine_subspace.pointwise_vadd_span AffineSubspace.pointwise_vadd_spanₓ'. -/
theorem pointwise_vadd_span (v : V) (s : Set P) : v +ᵥ affineSpan k s = affineSpan k (v +ᵥ s) :=
  map_span _ s
#align affine_subspace.pointwise_vadd_span AffineSubspace.pointwise_vadd_span

omit V

include V₁ V₂

/- warning: affine_subspace.map_pointwise_vadd -> AffineSubspace.map_pointwise_vadd is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} [_inst_1 : Ring.{u1} k] {V₁ : Type.{u2}} {P₁ : Type.{u3}} {V₂ : Type.{u4}} {P₂ : Type.{u5}} [_inst_5 : AddCommGroup.{u2} V₁] [_inst_6 : Module.{u1, u2} k V₁ (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V₁ _inst_5)] [_inst_7 : AddTorsor.{u2, u3} V₁ P₁ (AddCommGroup.toAddGroup.{u2} V₁ _inst_5)] [_inst_8 : AddCommGroup.{u4} V₂] [_inst_9 : Module.{u1, u4} k V₂ (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u4} V₂ _inst_8)] [_inst_10 : AddTorsor.{u4, u5} V₂ P₂ (AddCommGroup.toAddGroup.{u4} V₂ _inst_8)] (f : AffineMap.{u1, u2, u3, u4, u5} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10) (v : V₁) (s : AffineSubspace.{u1, u2, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7), Eq.{succ u5} (AffineSubspace.{u1, u4, u5} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (AffineSubspace.map.{u1, u2, u3, u4, u5} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10 f (VAdd.vadd.{u2, u3} V₁ (AffineSubspace.{u1, u2, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7) (AddAction.toHasVadd.{u2, u3} V₁ (AffineSubspace.{u1, u2, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7) (SubNegMonoid.toAddMonoid.{u2} V₁ (AddGroup.toSubNegMonoid.{u2} V₁ (AddCommGroup.toAddGroup.{u2} V₁ _inst_5))) (AffineSubspace.pointwiseAddAction.{u1, u2, u3} k _inst_1 V₁ P₁ _inst_5 _inst_6 _inst_7)) v s)) (VAdd.vadd.{u4, u5} V₂ (AffineSubspace.{u1, u4, u5} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (AddAction.toHasVadd.{u4, u5} V₂ (AffineSubspace.{u1, u4, u5} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (SubNegMonoid.toAddMonoid.{u4} V₂ (AddGroup.toSubNegMonoid.{u4} V₂ (AddCommGroup.toAddGroup.{u4} V₂ _inst_8))) (AffineSubspace.pointwiseAddAction.{u1, u4, u5} k _inst_1 V₂ P₂ _inst_8 _inst_9 _inst_10)) (coeFn.{max (succ u2) (succ u4), max (succ u2) (succ u4)} (LinearMap.{u1, u1, u2, u4} k k (Ring.toSemiring.{u1} k _inst_1) (Ring.toSemiring.{u1} k _inst_1) (RingHom.id.{u1} k (Semiring.toNonAssocSemiring.{u1} k (Ring.toSemiring.{u1} k _inst_1))) V₁ V₂ (AddCommGroup.toAddCommMonoid.{u2} V₁ _inst_5) (AddCommGroup.toAddCommMonoid.{u4} V₂ _inst_8) _inst_6 _inst_9) (fun (_x : LinearMap.{u1, u1, u2, u4} k k (Ring.toSemiring.{u1} k _inst_1) (Ring.toSemiring.{u1} k _inst_1) (RingHom.id.{u1} k (Semiring.toNonAssocSemiring.{u1} k (Ring.toSemiring.{u1} k _inst_1))) V₁ V₂ (AddCommGroup.toAddCommMonoid.{u2} V₁ _inst_5) (AddCommGroup.toAddCommMonoid.{u4} V₂ _inst_8) _inst_6 _inst_9) => V₁ -> V₂) (LinearMap.hasCoeToFun.{u1, u1, u2, u4} k k V₁ V₂ (Ring.toSemiring.{u1} k _inst_1) (Ring.toSemiring.{u1} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V₁ _inst_5) (AddCommGroup.toAddCommMonoid.{u4} V₂ _inst_8) _inst_6 _inst_9 (RingHom.id.{u1} k (Semiring.toNonAssocSemiring.{u1} k (Ring.toSemiring.{u1} k _inst_1)))) (AffineMap.linear.{u1, u2, u3, u4, u5} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10 f) v) (AffineSubspace.map.{u1, u2, u3, u4, u5} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10 f s))
but is expected to have type
  forall {k : Type.{u5}} [_inst_1 : Ring.{u5} k] {V₁ : Type.{u4}} {P₁ : Type.{u3}} {V₂ : Type.{u2}} {P₂ : Type.{u1}} [_inst_5 : AddCommGroup.{u4} V₁] [_inst_6 : Module.{u5, u4} k V₁ (Ring.toSemiring.{u5} k _inst_1) (AddCommGroup.toAddCommMonoid.{u4} V₁ _inst_5)] [_inst_7 : AddTorsor.{u4, u3} V₁ P₁ (AddCommGroup.toAddGroup.{u4} V₁ _inst_5)] [_inst_8 : AddCommGroup.{u2} V₂] [_inst_9 : Module.{u5, u2} k V₂ (Ring.toSemiring.{u5} k _inst_1) (AddCommGroup.toAddCommMonoid.{u2} V₂ _inst_8)] [_inst_10 : AddTorsor.{u2, u1} V₂ P₂ (AddCommGroup.toAddGroup.{u2} V₂ _inst_8)] (f : AffineMap.{u5, u4, u3, u2, u1} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10) (v : V₁) (s : AffineSubspace.{u5, u4, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7), Eq.{succ u1} (AffineSubspace.{u5, u2, u1} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (AffineSubspace.map.{u5, u4, u3, u2, u1} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10 f (HVAdd.hVAdd.{u4, u3, u3} V₁ (AffineSubspace.{u5, u4, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7) (AffineSubspace.{u5, u4, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7) (instHVAdd.{u4, u3} V₁ (AffineSubspace.{u5, u4, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7) (AddAction.toVAdd.{u4, u3} V₁ (AffineSubspace.{u5, u4, u3} k V₁ P₁ _inst_1 _inst_5 _inst_6 _inst_7) (SubNegMonoid.toAddMonoid.{u4} V₁ (AddGroup.toSubNegMonoid.{u4} V₁ (AddCommGroup.toAddGroup.{u4} V₁ _inst_5))) (AffineSubspace.pointwiseAddAction.{u5, u4, u3} k _inst_1 V₁ P₁ _inst_5 _inst_6 _inst_7))) v s)) (HVAdd.hVAdd.{u2, u1, u1} ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) (AffineSubspace.{u5, u2, u1} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (AffineSubspace.{u5, u2, u1} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (instHVAdd.{u2, u1} ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) (AffineSubspace.{u5, u2, u1} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (AddAction.toVAdd.{u2, u1} ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) (AffineSubspace.{u5, u2, u1} k V₂ P₂ _inst_1 _inst_8 _inst_9 _inst_10) (SubNegMonoid.toAddMonoid.{u2} ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) (AddGroup.toSubNegMonoid.{u2} ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) (AddCommGroup.toAddGroup.{u2} ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) _inst_8))) (AffineSubspace.pointwiseAddAction.{u5, u2, u1} k _inst_1 ((fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) v) P₂ _inst_8 _inst_9 _inst_10))) (FunLike.coe.{max (succ u4) (succ u2), succ u4, succ u2} (LinearMap.{u5, u5, u4, u2} k k (Ring.toSemiring.{u5} k _inst_1) (Ring.toSemiring.{u5} k _inst_1) (RingHom.id.{u5} k (Semiring.toNonAssocSemiring.{u5} k (Ring.toSemiring.{u5} k _inst_1))) V₁ V₂ (AddCommGroup.toAddCommMonoid.{u4} V₁ _inst_5) (AddCommGroup.toAddCommMonoid.{u2} V₂ _inst_8) _inst_6 _inst_9) V₁ (fun (_x : V₁) => (fun (x._@.Mathlib.Algebra.Module.LinearMap._hyg.6190 : V₁) => V₂) _x) (LinearMap.instFunLikeLinearMap.{u5, u5, u4, u2} k k V₁ V₂ (Ring.toSemiring.{u5} k _inst_1) (Ring.toSemiring.{u5} k _inst_1) (AddCommGroup.toAddCommMonoid.{u4} V₁ _inst_5) (AddCommGroup.toAddCommMonoid.{u2} V₂ _inst_8) _inst_6 _inst_9 (RingHom.id.{u5} k (Semiring.toNonAssocSemiring.{u5} k (Ring.toSemiring.{u5} k _inst_1)))) (AffineMap.linear.{u5, u4, u3, u2, u1} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10 f) v) (AffineSubspace.map.{u5, u4, u3, u2, u1} k V₁ P₁ V₂ P₂ _inst_1 _inst_5 _inst_6 _inst_7 _inst_8 _inst_9 _inst_10 f s))
Case conversion may be inaccurate. Consider using '#align affine_subspace.map_pointwise_vadd AffineSubspace.map_pointwise_vaddₓ'. -/
theorem map_pointwise_vadd (f : P₁ →ᵃ[k] P₂) (v : V₁) (s : AffineSubspace k P₁) :
    (v +ᵥ s).map f = f.linear v +ᵥ s.map f :=
  by
  unfold VAdd.vadd
  rw [map_map, map_map]
  congr 1
  ext
  exact f.map_vadd _ _
#align affine_subspace.map_pointwise_vadd AffineSubspace.map_pointwise_vadd

end AffineSubspace


/-
Copyright (c) 2020 Eric Wieser. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Simon Hudon, Patrick Massot, Eric Wieser
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.tactic.split_ifs
import Mathlib.tactic.simpa
import Mathlib.algebra.group.to_additive
import Mathlib.PostPort

universes u v u_1

namespace Mathlib

/-!
# Instances and theorems on pi types

This file provides basic definitions and notation instances for Pi types.

Instances of more sophisticated classes are defined in `pi.lean` files elsewhere.
-/

namespace pi

/-! `1`, `0`, `+`, `*`, `-`, `⁻¹`, and `/` are defined pointwise. -/

protected instance has_zero {I : Type u} {f : I → Type v} [(i : I) → HasZero (f i)] : HasZero ((i : I) → f i) :=
  { zero := fun (_x : I) => 0 }

@[simp] theorem one_apply {I : Type u} {f : I → Type v} (i : I) [(i : I) → HasOne (f i)] : HasOne.one i = 1 :=
  rfl

theorem one_def {I : Type u} {f : I → Type v} [(i : I) → HasOne (f i)] : 1 = fun (i : I) => 1 :=
  rfl

protected instance has_mul {I : Type u} {f : I → Type v} [(i : I) → Mul (f i)] : Mul ((i : I) → f i) :=
  { mul := fun (f_1 g : (i : I) → f i) (i : I) => f_1 i * g i }

@[simp] theorem mul_apply {I : Type u} {f : I → Type v} (x : (i : I) → f i) (y : (i : I) → f i) (i : I) [(i : I) → Mul (f i)] : Mul.mul x y i = x i * y i :=
  rfl

protected instance has_inv {I : Type u} {f : I → Type v} [(i : I) → has_inv (f i)] : has_inv ((i : I) → f i) :=
  has_inv.mk fun (f_1 : (i : I) → f i) (i : I) => f_1 i⁻¹

@[simp] theorem neg_apply {I : Type u} {f : I → Type v} (x : (i : I) → f i) (i : I) [(i : I) → Neg (f i)] : Neg.neg x i = -x i :=
  rfl

protected instance has_sub {I : Type u} {f : I → Type v} [(i : I) → Sub (f i)] : Sub ((i : I) → f i) :=
  { sub := fun (f_1 g : (i : I) → f i) (i : I) => f_1 i - g i }

@[simp] theorem sub_apply {I : Type u} {f : I → Type v} (x : (i : I) → f i) (y : (i : I) → f i) (i : I) [(i : I) → Sub (f i)] : Sub.sub x y i = x i - y i :=
  rfl

theorem div_def {I : Type u} {f : I → Type v} (x : (i : I) → f i) (y : (i : I) → f i) [(i : I) → Div (f i)] : x / y = fun (i : I) => x i / y i :=
  rfl

/-- The function supported at `i`, with value `x` there. -/
def single {I : Type u} {f : I → Type v} [DecidableEq I] [(i : I) → HasZero (f i)] (i : I) (x : f i) : (i : I) → f i :=
  function.update 0 i x

@[simp] theorem single_eq_same {I : Type u} {f : I → Type v} [DecidableEq I] [(i : I) → HasZero (f i)] (i : I) (x : f i) : single i x i = x :=
  function.update_same i x 0

@[simp] theorem single_eq_of_ne {I : Type u} {f : I → Type v} [DecidableEq I] [(i : I) → HasZero (f i)] {i : I} {i' : I} (h : i' ≠ i) (x : f i) : single i x i' = 0 :=
  function.update_noteq h x 0

theorem single_injective {I : Type u} (f : I → Type v) [DecidableEq I] [(i : I) → HasZero (f i)] (i : I) : function.injective (single i) :=
  function.update_injective (fun (a : I) => HasZero.zero a) i

end pi

theorem subsingleton.pi_single_eq {I : Type u} {α : Type u_1} [DecidableEq I] [subsingleton I] [HasZero α] (i : I) (x : α) : pi.single i x = fun (_x : I) => x := sorry


/-
Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Mario Carneiro
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.multiset.nodup
import Mathlib.PostPort

universes u_1 u_2

namespace Mathlib

/-!
# Erasing duplicates in a multiset.
-/

namespace multiset

/-! ### erase_dup -/

/-- `erase_dup s` removes duplicates from `s`, yielding a `nodup` multiset. -/
def erase_dup {α : Type u_1} [DecidableEq α] (s : multiset α) : multiset α :=
  quot.lift_on s (fun (l : List α) => ↑(list.erase_dup l)) sorry

@[simp] theorem coe_erase_dup {α : Type u_1} [DecidableEq α] (l : List α) :
    erase_dup ↑l = ↑(list.erase_dup l) :=
  rfl

@[simp] theorem erase_dup_zero {α : Type u_1} [DecidableEq α] : erase_dup 0 = 0 := rfl

@[simp] theorem mem_erase_dup {α : Type u_1} [DecidableEq α] {a : α} {s : multiset α} :
    a ∈ erase_dup s ↔ a ∈ s :=
  quot.induction_on s fun (l : List α) => list.mem_erase_dup

@[simp] theorem erase_dup_cons_of_mem {α : Type u_1} [DecidableEq α] {a : α} {s : multiset α} :
    a ∈ s → erase_dup (a ::ₘ s) = erase_dup s :=
  quot.induction_on s
    fun (l : List α) (m : a ∈ Quot.mk setoid.r l) => congr_arg coe (list.erase_dup_cons_of_mem m)

@[simp] theorem erase_dup_cons_of_not_mem {α : Type u_1} [DecidableEq α] {a : α} {s : multiset α} :
    ¬a ∈ s → erase_dup (a ::ₘ s) = a ::ₘ erase_dup s :=
  quot.induction_on s
    fun (l : List α) (m : ¬a ∈ Quot.mk setoid.r l) =>
      congr_arg coe (list.erase_dup_cons_of_not_mem m)

theorem erase_dup_le {α : Type u_1} [DecidableEq α] (s : multiset α) : erase_dup s ≤ s :=
  quot.induction_on s fun (l : List α) => list.sublist.subperm (list.erase_dup_sublist l)

theorem erase_dup_subset {α : Type u_1} [DecidableEq α] (s : multiset α) : erase_dup s ⊆ s :=
  subset_of_le (erase_dup_le s)

theorem subset_erase_dup {α : Type u_1} [DecidableEq α] (s : multiset α) : s ⊆ erase_dup s :=
  fun (a : α) => iff.mpr mem_erase_dup

@[simp] theorem erase_dup_subset' {α : Type u_1} [DecidableEq α] {s : multiset α} {t : multiset α} :
    erase_dup s ⊆ t ↔ s ⊆ t :=
  { mp := subset.trans (subset_erase_dup s), mpr := subset.trans (erase_dup_subset s) }

@[simp] theorem subset_erase_dup' {α : Type u_1} [DecidableEq α] {s : multiset α} {t : multiset α} :
    s ⊆ erase_dup t ↔ s ⊆ t :=
  { mp := fun (h : s ⊆ erase_dup t) => subset.trans h (erase_dup_subset t),
    mpr := fun (h : s ⊆ t) => subset.trans h (subset_erase_dup t) }

@[simp] theorem nodup_erase_dup {α : Type u_1} [DecidableEq α] (s : multiset α) :
    nodup (erase_dup s) :=
  quot.induction_on s list.nodup_erase_dup

theorem erase_dup_eq_self {α : Type u_1} [DecidableEq α] {s : multiset α} :
    erase_dup s = s ↔ nodup s :=
  sorry

theorem erase_dup_eq_zero {α : Type u_1} [DecidableEq α] {s : multiset α} :
    erase_dup s = 0 ↔ s = 0 :=
  { mp := fun (h : erase_dup s = 0) => eq_zero_of_subset_zero (h ▸ subset_erase_dup s),
    mpr := fun (h : s = 0) => Eq.symm h ▸ erase_dup_zero }

@[simp] theorem erase_dup_singleton {α : Type u_1} [DecidableEq α] {a : α} :
    erase_dup (a ::ₘ 0) = a ::ₘ 0 :=
  iff.mpr erase_dup_eq_self (nodup_singleton a)

theorem le_erase_dup {α : Type u_1} [DecidableEq α] {s : multiset α} {t : multiset α} :
    s ≤ erase_dup t ↔ s ≤ t ∧ nodup s :=
  sorry

theorem erase_dup_ext {α : Type u_1} [DecidableEq α] {s : multiset α} {t : multiset α} :
    erase_dup s = erase_dup t ↔ ∀ (a : α), a ∈ s ↔ a ∈ t :=
  sorry

theorem erase_dup_map_erase_dup_eq {α : Type u_1} {β : Type u_2} [DecidableEq α] [DecidableEq β]
    (f : α → β) (s : multiset α) : erase_dup (map f (erase_dup s)) = erase_dup (map f s) :=
  sorry

@[simp] theorem erase_dup_nsmul {α : Type u_1} [DecidableEq α] {s : multiset α} {n : ℕ}
    (h0 : n ≠ 0) : erase_dup (n •ℕ s) = erase_dup s :=
  sorry

theorem nodup.le_erase_dup_iff_le {α : Type u_1} [DecidableEq α] {s : multiset α} {t : multiset α}
    (hno : nodup s) : s ≤ erase_dup t ↔ s ≤ t :=
  sorry

end multiset

theorem multiset.nodup.le_nsmul_iff_le {α : Type u_1} {s : multiset α} {t : multiset α} {n : ℕ}
    (h : multiset.nodup s) (hn : n ≠ 0) : s ≤ n •ℕ t ↔ s ≤ t :=
  sorry

end Mathlib


/-
Copyright (c) 2016 Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Robert Y. Lewis

Derivatives on ℝ
-/
import .bounded_linear_operator
open real nat classical topology analysis set
noncomputable theory

namespace real

-- make instance of const mul bdd lin op?

definition has_deriv_at (f : ℝ → ℝ) (d x : ℝ) := has_frechet_deriv_at f (λ t, d • t) x

theorem has_deriv_at_intro (f : ℝ → ℝ) (d x : ℝ) (H : (λ h, (f (x + h) - f x) / h) ⟶ d [at 0]) :
        has_deriv_at f d x :=
  begin
    apply has_frechet_deriv_at_intro,
    intros ε Hε,
    cases approaches_at_dest H Hε with δ Hδ,
    existsi δ,
    split,
    exact and.left Hδ,
    intro y Hy,
    rewrite [-sub_zero y at Hy{2}],
    note Hδ' := and.right Hδ y (and.right Hy) (and.left Hy),
    have Hδ'' : abs ((f (x + y) - f x - d * y) / y) < ε,
      by rewrite [-div_sub_div_same, mul_div_cancel _ (and.left Hy)]; apply Hδ',
    show abs (f (x + y) - f x - d * y) / abs y < ε, by rewrite -abs_div; apply Hδ''
  end

theorem has_deriv_at_of_has_frechet_deriv_at {f g : ℝ → ℝ} [is_bdd_linear_map g] {d x : ℝ}
        (H : has_frechet_deriv_at f g x) (Hg : g = λ x, d * x) :
        has_deriv_at f d x :=
  by apply is_frechet_deriv_at_of_eq H Hg

theorem has_deriv_at_const (c x : ℝ) : has_deriv_at (λ t, c) 0 x :=
  has_deriv_at_of_has_frechet_deriv_at
    (@has_frechet_deriv_at_const ℝ ℝ _ _ _ c)
    (funext (λ v, by rewrite zero_mul))

theorem has_deriv_at_id (x : ℝ) : has_deriv_at (λ t, t) 1 x :=
  has_deriv_at_of_has_frechet_deriv_at
    (@has_frechet_deriv_at_id ℝ ℝ _ _ _)
    (funext (λ v, by rewrite one_mul))

theorem has_deriv_at_mul {f : ℝ → ℝ} {d x : ℝ} (H : has_deriv_at f d x) (c : ℝ) :
        has_deriv_at (λ t, c * f t) (c * d) x :=
  has_deriv_at_of_has_frechet_deriv_at
    (has_frechet_deriv_at_smul _ _ c H)
    (funext (λ v, by rewrite mul.assoc))

end real


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

! This file was ported from Lean 3 source module ring_theory.graded_algebra.homogeneous_ideal
! leanprover-community/mathlib commit 4e861f25ba5ceef42ba0712d8ffeb32f38ad6441
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.RingTheory.Ideal.Basic
import Mathbin.RingTheory.Ideal.Operations
import Mathbin.LinearAlgebra.Finsupp
import Mathbin.RingTheory.GradedAlgebra.Basic

/-!
# Homogeneous ideals of a graded algebra

This file defines homogeneous ideals of `graded_ring 𝒜` where `𝒜 : ι → submodule R A` and
operations on them.

## Main definitions

For any `I : ideal A`:
* `ideal.is_homogeneous 𝒜 I`: The property that an ideal is closed under `graded_ring.proj`.
* `homogeneous_ideal 𝒜`: The structure extending ideals which satisfy `ideal.is_homogeneous`
* `ideal.homogeneous_core I 𝒜`: The largest homogeneous ideal smaller than `I`.
* `ideal.homogeneous_hull I 𝒜`: The smallest homogeneous ideal larger than `I`.

## Main statements

* `homogeneous_ideal.complete_lattice`: `ideal.is_homogeneous` is preserved by `⊥`, `⊤`, `⊔`, `⊓`,
  `⨆`, `⨅`, and so the subtype of homogeneous ideals inherits a complete lattice structure.
* `ideal.homogeneous_core.gi`: `ideal.homogeneous_core` forms a galois insertion with coercion.
* `ideal.homogeneous_hull.gi`: `ideal.homogeneous_hull` forms a galois insertion with coercion.

## Implementation notes

We introduce `ideal.homogeneous_core'` earlier than might be expected so that we can get access
to `ideal.is_homogeneous.iff_exists` as quickly as possible.

## Tags

graded algebra, homogeneous
-/

open SetLike DirectSum Set

open BigOperators Pointwise DirectSum

variable {ι σ R A : Type _}

section HomogeneousDef

variable [Semiring A]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ)

variable [DecidableEq ι] [AddMonoid ι] [GradedRing 𝒜]

variable (I : Ideal A)

include A

/-- An `I : ideal A` is homogeneous if for every `r ∈ I`, all homogeneous components
  of `r` are in `I`.-/
def Ideal.IsHomogeneous : Prop :=
  ∀ (i : ι) ⦃r : A⦄, r ∈ I → (DirectSum.decompose 𝒜 r i : A) ∈ I
#align ideal.is_homogeneous Ideal.IsHomogeneous

/-- For any `semiring A`, we collect the homogeneous ideals of `A` into a type. -/
structure HomogeneousIdeal extends Submodule A A where
  isHomogeneous' : Ideal.IsHomogeneous 𝒜 to_submodule
#align homogeneous_ideal HomogeneousIdeal

variable {𝒜}

/-- Converting a homogeneous ideal to an ideal-/
def HomogeneousIdeal.toIdeal (I : HomogeneousIdeal 𝒜) : Ideal A :=
  I.toSubmodule
#align homogeneous_ideal.to_ideal HomogeneousIdeal.toIdeal

theorem HomogeneousIdeal.isHomogeneous (I : HomogeneousIdeal 𝒜) : I.toIdeal.Homogeneous 𝒜 :=
  I.isHomogeneous'
#align homogeneous_ideal.is_homogeneous HomogeneousIdeal.isHomogeneous

theorem HomogeneousIdeal.toIdeal_injective :
    Function.Injective (HomogeneousIdeal.toIdeal : HomogeneousIdeal 𝒜 → Ideal A) :=
  fun ⟨x, hx⟩ ⟨y, hy⟩ (h : x = y) => by simp [h]
#align homogeneous_ideal.to_ideal_injective HomogeneousIdeal.toIdeal_injective

instance HomogeneousIdeal.setLike : SetLike (HomogeneousIdeal 𝒜) A
    where
  coe I := I.toIdeal
  coe_injective' I J h := HomogeneousIdeal.toIdeal_injective <| SetLike.coe_injective h
#align homogeneous_ideal.set_like HomogeneousIdeal.setLike

@[ext]
theorem HomogeneousIdeal.ext {I J : HomogeneousIdeal 𝒜} (h : I.toIdeal = J.toIdeal) : I = J :=
  HomogeneousIdeal.toIdeal_injective h
#align homogeneous_ideal.ext HomogeneousIdeal.ext

@[simp]
theorem HomogeneousIdeal.mem_iff {I : HomogeneousIdeal 𝒜} {x : A} : x ∈ I.toIdeal ↔ x ∈ I :=
  Iff.rfl
#align homogeneous_ideal.mem_iff HomogeneousIdeal.mem_iff

end HomogeneousDef

section HomogeneousCore

variable [Semiring A]

variable [SetLike σ A] (𝒜 : ι → σ)

variable (I : Ideal A)

include A

/-- For any `I : ideal A`, not necessarily homogeneous, `I.homogeneous_core' 𝒜`
is the largest homogeneous ideal of `A` contained in `I`, as an ideal. -/
def Ideal.homogeneousCore' (I : Ideal A) : Ideal A :=
  Ideal.span (coe '' ((coe : Subtype (Homogeneous 𝒜) → A) ⁻¹' I))
#align ideal.homogeneous_core' Ideal.homogeneousCore'

theorem Ideal.homogeneousCore'_mono : Monotone (Ideal.homogeneousCore' 𝒜) := fun I J I_le_J =>
  Ideal.span_mono <| Set.image_subset _ fun x => @I_le_J _
#align ideal.homogeneous_core'_mono Ideal.homogeneousCore'_mono

theorem Ideal.homogeneousCore'_le : I.homogeneousCore' 𝒜 ≤ I :=
  Ideal.span_le.2 <| image_preimage_subset _ _
#align ideal.homogeneous_core'_le Ideal.homogeneousCore'_le

end HomogeneousCore

section IsHomogeneousIdealDefs

variable [Semiring A]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ)

variable [DecidableEq ι] [AddMonoid ι] [GradedRing 𝒜]

variable (I : Ideal A)

include A

theorem Ideal.isHomogeneous_iff_forall_subset :
    I.Homogeneous 𝒜 ↔ ∀ i, (I : Set A) ⊆ GradedRing.proj 𝒜 i ⁻¹' I :=
  Iff.rfl
#align ideal.is_homogeneous_iff_forall_subset Ideal.isHomogeneous_iff_forall_subset

theorem Ideal.isHomogeneous_iff_subset_interᵢ :
    I.Homogeneous 𝒜 ↔ (I : Set A) ⊆ ⋂ i, GradedRing.proj 𝒜 i ⁻¹' ↑I :=
  subset_interᵢ_iff.symm
#align ideal.is_homogeneous_iff_subset_Inter Ideal.isHomogeneous_iff_subset_interᵢ

theorem Ideal.mul_homogeneous_element_mem_of_mem {I : Ideal A} (r x : A) (hx₁ : Homogeneous 𝒜 x)
    (hx₂ : x ∈ I) (j : ι) : GradedRing.proj 𝒜 j (r * x) ∈ I := by
  classical
    rw [← DirectSum.sum_support_decompose 𝒜 r, Finset.sum_mul, map_sum]
    apply Ideal.sum_mem
    intro k hk
    obtain ⟨i, hi⟩ := hx₁
    have mem₁ : (DirectSum.decompose 𝒜 r k : A) * x ∈ 𝒜 (k + i) :=
      graded_monoid.mul_mem (SetLike.coe_mem _) hi
    erw [GradedRing.proj_apply, DirectSum.decompose_of_mem 𝒜 mem₁, coe_of_apply, [anonymous]]
    split_ifs
    · exact I.mul_mem_left _ hx₂
    · exact I.zero_mem
#align ideal.mul_homogeneous_element_mem_of_mem Ideal.mul_homogeneous_element_mem_of_mem

theorem Ideal.isHomogeneousSpan (s : Set A) (h : ∀ x ∈ s, Homogeneous 𝒜 x) :
    (Ideal.span s).Homogeneous 𝒜 := by
  rintro i r hr
  rw [Ideal.span, Finsupp.span_eq_range_total] at hr
  rw [LinearMap.mem_range] at hr
  obtain ⟨s, rfl⟩ := hr
  rw [Finsupp.total_apply, Finsupp.sum, decompose_sum, Dfinsupp.finset_sum_apply,
    AddSubmonoidClass.coe_finset_sum]
  refine' Ideal.sum_mem _ _
  rintro z hz1
  rw [smul_eq_mul]
  refine' Ideal.mul_homogeneous_element_mem_of_mem 𝒜 (s z) z _ _ i
  · rcases z with ⟨z, hz2⟩
    apply h _ hz2
  · exact Ideal.subset_span z.2
#align ideal.is_homogeneous_span Ideal.isHomogeneousSpan

/-- For any `I : ideal A`, not necessarily homogeneous, `I.homogeneous_core' 𝒜`
is the largest homogeneous ideal of `A` contained in `I`.-/
def Ideal.homogeneousCore : HomogeneousIdeal 𝒜 :=
  ⟨Ideal.homogeneousCore' 𝒜 I,
    Ideal.isHomogeneousSpan _ _ fun x h =>
      by
      rw [Subtype.image_preimage_coe] at h
      exact h.2⟩
#align ideal.homogeneous_core Ideal.homogeneousCore

theorem Ideal.homogeneousCore_mono : Monotone (Ideal.homogeneousCore 𝒜) :=
  Ideal.homogeneousCore'_mono 𝒜
#align ideal.homogeneous_core_mono Ideal.homogeneousCore_mono

theorem Ideal.toIdeal_homogeneousCore_le : (I.homogeneousCore 𝒜).toIdeal ≤ I :=
  Ideal.homogeneousCore'_le 𝒜 I
#align ideal.to_ideal_homogeneous_core_le Ideal.toIdeal_homogeneousCore_le

variable {𝒜 I}

theorem Ideal.mem_homogeneousCore_of_homogeneous_of_mem {x : A} (h : SetLike.Homogeneous 𝒜 x)
    (hmem : x ∈ I) : x ∈ I.homogeneousCore 𝒜 :=
  Ideal.subset_span ⟨⟨x, h⟩, hmem, rfl⟩
#align ideal.mem_homogeneous_core_of_is_homogeneous_of_mem Ideal.mem_homogeneousCore_of_homogeneous_of_mem

theorem Ideal.IsHomogeneous.toIdeal_homogeneousCore_eq_self (h : I.Homogeneous 𝒜) :
    (I.homogeneousCore 𝒜).toIdeal = I :=
  by
  apply le_antisymm (I.homogeneous_core'_le 𝒜) _
  intro x hx
  classical
    rw [← DirectSum.sum_support_decompose 𝒜 x]
    exact Ideal.sum_mem _ fun j hj => Ideal.subset_span ⟨⟨_, is_homogeneous_coe _⟩, h _ hx, rfl⟩
#align ideal.is_homogeneous.to_ideal_homogeneous_core_eq_self Ideal.IsHomogeneous.toIdeal_homogeneousCore_eq_self

@[simp]
theorem HomogeneousIdeal.toIdeal_homogeneousCore_eq_self (I : HomogeneousIdeal 𝒜) :
    I.toIdeal.homogeneousCore 𝒜 = I := by
  ext1 <;> convert Ideal.IsHomogeneous.toIdeal_homogeneousCore_eq_self I.is_homogeneous
#align homogeneous_ideal.to_ideal_homogeneous_core_eq_self HomogeneousIdeal.toIdeal_homogeneousCore_eq_self

variable (𝒜 I)

theorem Ideal.IsHomogeneous.iff_eq : I.Homogeneous 𝒜 ↔ (I.homogeneousCore 𝒜).toIdeal = I :=
  ⟨fun hI => hI.toIdeal_homogeneousCore_eq_self, fun hI => hI ▸ (Ideal.homogeneousCore 𝒜 I).2⟩
#align ideal.is_homogeneous.iff_eq Ideal.IsHomogeneous.iff_eq

theorem Ideal.IsHomogeneous.iff_exists :
    I.Homogeneous 𝒜 ↔ ∃ S : Set (homogeneousSubmonoid 𝒜), I = Ideal.span (coe '' S) :=
  by
  rw [Ideal.IsHomogeneous.iff_eq, eq_comm]
  exact ((set.image_preimage.compose (Submodule.gi _ _).gc).exists_eq_l _).symm
#align ideal.is_homogeneous.iff_exists Ideal.IsHomogeneous.iff_exists

end IsHomogeneousIdealDefs

/-! ### Operations

In this section, we show that `ideal.is_homogeneous` is preserved by various notations, then use
these results to provide these notation typeclasses for `homogeneous_ideal`. -/

section Operations

section Semiring

variable [Semiring A] [DecidableEq ι] [AddMonoid ι]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ) [GradedRing 𝒜]

include A

namespace Ideal.IsHomogeneous

theorem bot : Ideal.IsHomogeneous 𝒜 ⊥ := fun i r hr =>
  by
  simp only [Ideal.mem_bot] at hr
  rw [hr, decompose_zero, zero_apply]
  apply Ideal.zero_mem
#align ideal.is_homogeneous.bot Ideal.IsHomogeneous.bot

theorem top : Ideal.IsHomogeneous 𝒜 ⊤ := fun i r hr => by simp only [Submodule.mem_top]
#align ideal.is_homogeneous.top Ideal.IsHomogeneous.top

variable {𝒜}

theorem inf {I J : Ideal A} (HI : I.Homogeneous 𝒜) (HJ : J.Homogeneous 𝒜) : (I ⊓ J).Homogeneous 𝒜 :=
  fun i r hr => ⟨HI _ hr.1, HJ _ hr.2⟩
#align ideal.is_homogeneous.inf Ideal.IsHomogeneous.inf

theorem sup {I J : Ideal A} (HI : I.Homogeneous 𝒜) (HJ : J.Homogeneous 𝒜) : (I ⊔ J).Homogeneous 𝒜 :=
  by
  rw [iff_exists] at HI HJ⊢
  obtain ⟨⟨s₁, rfl⟩, ⟨s₂, rfl⟩⟩ := HI, HJ
  refine' ⟨s₁ ∪ s₂, _⟩
  rw [Set.image_union]
  exact (Submodule.span_union _ _).symm
#align ideal.is_homogeneous.sup Ideal.IsHomogeneous.sup

protected theorem supr {κ : Sort _} {f : κ → Ideal A} (h : ∀ i, (f i).Homogeneous 𝒜) :
    (⨆ i, f i).Homogeneous 𝒜 := by
  simp_rw [iff_exists] at h⊢
  choose s hs using h
  refine' ⟨⋃ i, s i, _⟩
  simp_rw [Set.image_unionᵢ, Ideal.span_unionᵢ]
  congr
  exact funext hs
#align ideal.is_homogeneous.supr Ideal.IsHomogeneous.supr

protected theorem infi {κ : Sort _} {f : κ → Ideal A} (h : ∀ i, (f i).Homogeneous 𝒜) :
    (⨅ i, f i).Homogeneous 𝒜 := by
  intro i x hx
  simp only [Ideal.mem_infᵢ] at hx⊢
  exact fun j => h _ _ (hx j)
#align ideal.is_homogeneous.infi Ideal.IsHomogeneous.infi

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
theorem supr₂ {κ : Sort _} {κ' : κ → Sort _} {f : ∀ i, κ' i → Ideal A}
    (h : ∀ i j, (f i j).Homogeneous 𝒜) : (⨆ (i) (j), f i j).Homogeneous 𝒜 :=
  IsHomogeneous.supr fun i => IsHomogeneous.supr <| h i
#align ideal.is_homogeneous.supr₂ Ideal.IsHomogeneous.supr₂

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
theorem infi₂ {κ : Sort _} {κ' : κ → Sort _} {f : ∀ i, κ' i → Ideal A}
    (h : ∀ i j, (f i j).Homogeneous 𝒜) : (⨅ (i) (j), f i j).Homogeneous 𝒜 :=
  IsHomogeneous.infi fun i => IsHomogeneous.infi <| h i
#align ideal.is_homogeneous.infi₂ Ideal.IsHomogeneous.infi₂

/- warning: ideal.is_homogeneous.Sup clashes with ideal.is_homogeneous.sup -> Ideal.IsHomogeneous.sup
Case conversion may be inaccurate. Consider using '#align ideal.is_homogeneous.Sup Ideal.IsHomogeneous.supₓ'. -/
#print Ideal.IsHomogeneous.sup /-
theorem sup {ℐ : Set (Ideal A)} (h : ∀ I ∈ ℐ, Ideal.IsHomogeneous 𝒜 I) : (supₛ ℐ).Homogeneous 𝒜 :=
  by
  rw [supₛ_eq_supᵢ]
  exact supr₂ h
#align ideal.is_homogeneous.Sup Ideal.IsHomogeneous.sup
-/

/- warning: ideal.is_homogeneous.Inf clashes with ideal.is_homogeneous.inf -> Ideal.IsHomogeneous.inf
Case conversion may be inaccurate. Consider using '#align ideal.is_homogeneous.Inf Ideal.IsHomogeneous.infₓ'. -/
#print Ideal.IsHomogeneous.inf /-
theorem inf {ℐ : Set (Ideal A)} (h : ∀ I ∈ ℐ, Ideal.IsHomogeneous 𝒜 I) : (infₛ ℐ).Homogeneous 𝒜 :=
  by
  rw [infₛ_eq_infᵢ]
  exact infi₂ h
#align ideal.is_homogeneous.Inf Ideal.IsHomogeneous.inf
-/

end Ideal.IsHomogeneous

variable {𝒜}

namespace HomogeneousIdeal

instance : PartialOrder (HomogeneousIdeal 𝒜) :=
  SetLike.partialOrder

instance : Top (HomogeneousIdeal 𝒜) :=
  ⟨⟨⊤, Ideal.IsHomogeneous.top 𝒜⟩⟩

instance : Bot (HomogeneousIdeal 𝒜) :=
  ⟨⟨⊥, Ideal.IsHomogeneous.bot 𝒜⟩⟩

instance : Sup (HomogeneousIdeal 𝒜) :=
  ⟨fun I J => ⟨_, I.Homogeneous.sup J.Homogeneous⟩⟩

instance : Inf (HomogeneousIdeal 𝒜) :=
  ⟨fun I J => ⟨_, I.Homogeneous.inf J.Homogeneous⟩⟩

instance : SupSet (HomogeneousIdeal 𝒜) :=
  ⟨fun S => ⟨⨆ s ∈ S, toIdeal s, Ideal.IsHomogeneous.supr₂ fun s _ => s.Homogeneous⟩⟩

instance : InfSet (HomogeneousIdeal 𝒜) :=
  ⟨fun S => ⟨⨅ s ∈ S, toIdeal s, Ideal.IsHomogeneous.infi₂ fun s _ => s.Homogeneous⟩⟩

@[simp]
theorem coe_top : ((⊤ : HomogeneousIdeal 𝒜) : Set A) = univ :=
  rfl
#align homogeneous_ideal.coe_top HomogeneousIdeal.coe_top

@[simp]
theorem coe_bot : ((⊥ : HomogeneousIdeal 𝒜) : Set A) = 0 :=
  rfl
#align homogeneous_ideal.coe_bot HomogeneousIdeal.coe_bot

@[simp]
theorem coe_sup (I J : HomogeneousIdeal 𝒜) : ↑(I ⊔ J) = (I + J : Set A) :=
  Submodule.coe_sup _ _
#align homogeneous_ideal.coe_sup HomogeneousIdeal.coe_sup

@[simp]
theorem coe_inf (I J : HomogeneousIdeal 𝒜) : (↑(I ⊓ J) : Set A) = I ∩ J :=
  rfl
#align homogeneous_ideal.coe_inf HomogeneousIdeal.coe_inf

@[simp]
theorem toIdeal_top : (⊤ : HomogeneousIdeal 𝒜).toIdeal = (⊤ : Ideal A) :=
  rfl
#align homogeneous_ideal.to_ideal_top HomogeneousIdeal.toIdeal_top

@[simp]
theorem toIdeal_bot : (⊥ : HomogeneousIdeal 𝒜).toIdeal = (⊥ : Ideal A) :=
  rfl
#align homogeneous_ideal.to_ideal_bot HomogeneousIdeal.toIdeal_bot

@[simp]
theorem toIdeal_sup (I J : HomogeneousIdeal 𝒜) : (I ⊔ J).toIdeal = I.toIdeal ⊔ J.toIdeal :=
  rfl
#align homogeneous_ideal.to_ideal_sup HomogeneousIdeal.toIdeal_sup

@[simp]
theorem toIdeal_inf (I J : HomogeneousIdeal 𝒜) : (I ⊓ J).toIdeal = I.toIdeal ⊓ J.toIdeal :=
  rfl
#align homogeneous_ideal.to_ideal_inf HomogeneousIdeal.toIdeal_inf

@[simp]
theorem toIdeal_supₛ (ℐ : Set (HomogeneousIdeal 𝒜)) : (supₛ ℐ).toIdeal = ⨆ s ∈ ℐ, toIdeal s :=
  rfl
#align homogeneous_ideal.to_ideal_Sup HomogeneousIdeal.toIdeal_supₛ

@[simp]
theorem toIdeal_infₛ (ℐ : Set (HomogeneousIdeal 𝒜)) : (infₛ ℐ).toIdeal = ⨅ s ∈ ℐ, toIdeal s :=
  rfl
#align homogeneous_ideal.to_ideal_Inf HomogeneousIdeal.toIdeal_infₛ

@[simp]
theorem toIdeal_supᵢ {κ : Sort _} (s : κ → HomogeneousIdeal 𝒜) :
    (⨆ i, s i).toIdeal = ⨆ i, (s i).toIdeal := by rw [supᵢ, to_ideal_Sup, supᵢ_range]
#align homogeneous_ideal.to_ideal_supr HomogeneousIdeal.toIdeal_supᵢ

@[simp]
theorem toIdeal_infᵢ {κ : Sort _} (s : κ → HomogeneousIdeal 𝒜) :
    (⨅ i, s i).toIdeal = ⨅ i, (s i).toIdeal := by rw [infᵢ, to_ideal_Inf, infᵢ_range]
#align homogeneous_ideal.to_ideal_infi HomogeneousIdeal.toIdeal_infᵢ

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[simp]
theorem toIdeal_supr₂ {κ : Sort _} {κ' : κ → Sort _} (s : ∀ i, κ' i → HomogeneousIdeal 𝒜) :
    (⨆ (i) (j), s i j).toIdeal = ⨆ (i) (j), (s i j).toIdeal := by simp_rw [to_ideal_supr]
#align homogeneous_ideal.to_ideal_supr₂ HomogeneousIdeal.toIdeal_supr₂

/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
@[simp]
theorem toIdeal_infi₂ {κ : Sort _} {κ' : κ → Sort _} (s : ∀ i, κ' i → HomogeneousIdeal 𝒜) :
    (⨅ (i) (j), s i j).toIdeal = ⨅ (i) (j), (s i j).toIdeal := by simp_rw [to_ideal_infi]
#align homogeneous_ideal.to_ideal_infi₂ HomogeneousIdeal.toIdeal_infi₂

@[simp]
theorem eq_top_iff (I : HomogeneousIdeal 𝒜) : I = ⊤ ↔ I.toIdeal = ⊤ :=
  toIdeal_injective.eq_iff.symm
#align homogeneous_ideal.eq_top_iff HomogeneousIdeal.eq_top_iff

@[simp]
theorem eq_bot_iff (I : HomogeneousIdeal 𝒜) : I = ⊥ ↔ I.toIdeal = ⊥ :=
  toIdeal_injective.eq_iff.symm
#align homogeneous_ideal.eq_bot_iff HomogeneousIdeal.eq_bot_iff

instance : CompleteLattice (HomogeneousIdeal 𝒜) :=
  toIdeal_injective.CompleteLattice _ toIdeal_sup toIdeal_inf toIdeal_supₛ toIdeal_infₛ toIdeal_top
    toIdeal_bot

instance : Add (HomogeneousIdeal 𝒜) :=
  ⟨(· ⊔ ·)⟩

@[simp]
theorem toIdeal_add (I J : HomogeneousIdeal 𝒜) : (I + J).toIdeal = I.toIdeal + J.toIdeal :=
  rfl
#align homogeneous_ideal.to_ideal_add HomogeneousIdeal.toIdeal_add

instance : Inhabited (HomogeneousIdeal 𝒜) where default := ⊥

end HomogeneousIdeal

end Semiring

section CommSemiring

variable [CommSemiring A]

variable [DecidableEq ι] [AddMonoid ι]

variable [SetLike σ A] [AddSubmonoidClass σ A] {𝒜 : ι → σ} [GradedRing 𝒜]

variable (I : Ideal A)

include A

theorem Ideal.IsHomogeneous.mul {I J : Ideal A} (HI : I.Homogeneous 𝒜) (HJ : J.Homogeneous 𝒜) :
    (I * J).Homogeneous 𝒜 :=
  by
  rw [Ideal.IsHomogeneous.iff_exists] at HI HJ⊢
  obtain ⟨⟨s₁, rfl⟩, ⟨s₂, rfl⟩⟩ := HI, HJ
  rw [Ideal.span_mul_span']
  exact ⟨s₁ * s₂, congr_arg _ <| (Set.image_mul (homogeneous_submonoid 𝒜).Subtype).symm⟩
#align ideal.is_homogeneous.mul Ideal.IsHomogeneous.mul

variable {𝒜}

instance : Mul (HomogeneousIdeal 𝒜)
    where mul I J := ⟨I.toIdeal * J.toIdeal, I.Homogeneous.mul J.Homogeneous⟩

@[simp]
theorem HomogeneousIdeal.toIdeal_mul (I J : HomogeneousIdeal 𝒜) :
    (I * J).toIdeal = I.toIdeal * J.toIdeal :=
  rfl
#align homogeneous_ideal.to_ideal_mul HomogeneousIdeal.toIdeal_mul

end CommSemiring

end Operations

/-! ### Homogeneous core

Note that many results about the homogeneous core came earlier in this file, as they are helpful
for building the lattice structure. -/

section HomogeneousCore

open HomogeneousIdeal

variable [Semiring A] [DecidableEq ι] [AddMonoid ι]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ) [GradedRing 𝒜]

variable (I : Ideal A)

include A

theorem Ideal.homogeneousCore.gc : GaloisConnection toIdeal (Ideal.homogeneousCore 𝒜) := fun I J =>
  ⟨fun H => I.toIdeal_homogeneousCore_eq_self ▸ Ideal.homogeneousCore_mono 𝒜 H, fun H =>
    le_trans H (Ideal.homogeneousCore'_le _ _)⟩
#align ideal.homogeneous_core.gc Ideal.homogeneousCore.gc

/-- `to_ideal : homogeneous_ideal 𝒜 → ideal A` and `ideal.homogeneous_core 𝒜` forms a galois
coinsertion-/
def Ideal.homogeneousCore.gi : GaloisCoinsertion toIdeal (Ideal.homogeneousCore 𝒜)
    where
  choice I HI :=
    ⟨I, le_antisymm (I.toIdeal_homogeneousCore_le 𝒜) HI ▸ HomogeneousIdeal.isHomogeneous _⟩
  gc := Ideal.homogeneousCore.gc 𝒜
  u_l_le I := Ideal.homogeneousCore'_le _ _
  choice_eq I H := le_antisymm H (I.toIdeal_homogeneousCore_le _)
#align ideal.homogeneous_core.gi Ideal.homogeneousCore.gi

theorem Ideal.homogeneousCore_eq_supₛ :
    I.homogeneousCore 𝒜 = supₛ { J : HomogeneousIdeal 𝒜 | J.toIdeal ≤ I } :=
  Eq.symm <| IsLUB.supₛ_eq <| (Ideal.homogeneousCore.gc 𝒜).isGreatest_u.IsLUB
#align ideal.homogeneous_core_eq_Sup Ideal.homogeneousCore_eq_supₛ

theorem Ideal.homogeneousCore'_eq_supₛ :
    I.homogeneousCore' 𝒜 = supₛ { J : Ideal A | J.Homogeneous 𝒜 ∧ J ≤ I } :=
  by
  refine' (IsLUB.supₛ_eq _).symm
  apply IsGreatest.isLUB
  have coe_mono : Monotone (to_ideal : HomogeneousIdeal 𝒜 → Ideal A) := fun x y => id
  convert coe_mono.map_is_greatest (Ideal.homogeneousCore.gc 𝒜).isGreatest_u using 1
  ext
  rw [mem_image, mem_set_of_eq]
  refine'
    ⟨fun hI => ⟨⟨x, hI.1⟩, ⟨hI.2, rfl⟩⟩, by rintro ⟨x, ⟨hx, rfl⟩⟩ <;> exact ⟨x.is_homogeneous, hx⟩⟩
#align ideal.homogeneous_core'_eq_Sup Ideal.homogeneousCore'_eq_supₛ

end HomogeneousCore

/-! ### Homogeneous hulls -/

section HomogeneousHull

open HomogeneousIdeal

variable [Semiring A] [DecidableEq ι] [AddMonoid ι]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ) [GradedRing 𝒜]

variable (I : Ideal A)

include A

/-- For any `I : ideal A`, not necessarily homogeneous, `I.homogeneous_hull 𝒜` is
the smallest homogeneous ideal containing `I`. -/
def Ideal.homogeneousHull : HomogeneousIdeal 𝒜 :=
  ⟨Ideal.span { r : A | ∃ (i : ι)(x : I), (DirectSum.decompose 𝒜 (x : A) i : A) = r },
    by
    refine' Ideal.isHomogeneousSpan _ _ fun x hx => _
    obtain ⟨i, x, rfl⟩ := hx
    apply SetLike.homogeneous_coe⟩
#align ideal.homogeneous_hull Ideal.homogeneousHull

theorem Ideal.le_toIdeal_homogeneousHull : I ≤ (Ideal.homogeneousHull 𝒜 I).toIdeal :=
  by
  intro r hr
  classical
    rw [← DirectSum.sum_support_decompose 𝒜 r]
    refine' Ideal.sum_mem _ _
    intro j hj
    apply Ideal.subset_span
    use j
    use ⟨r, hr⟩
    rfl
#align ideal.le_to_ideal_homogeneous_hull Ideal.le_toIdeal_homogeneousHull

theorem Ideal.homogeneousHull_mono : Monotone (Ideal.homogeneousHull 𝒜) := fun I J I_le_J =>
  by
  apply Ideal.span_mono
  rintro r ⟨hr1, ⟨x, hx⟩, rfl⟩
  refine' ⟨hr1, ⟨⟨x, I_le_J hx⟩, rfl⟩⟩
#align ideal.homogeneous_hull_mono Ideal.homogeneousHull_mono

variable {I 𝒜}

theorem Ideal.IsHomogeneous.toIdeal_homogeneousHull_eq_self (h : I.Homogeneous 𝒜) :
    (Ideal.homogeneousHull 𝒜 I).toIdeal = I :=
  by
  apply le_antisymm _ (Ideal.le_toIdeal_homogeneousHull _ _)
  apply Ideal.span_le.2
  rintro _ ⟨i, x, rfl⟩
  exact h _ x.prop
#align ideal.is_homogeneous.to_ideal_homogeneous_hull_eq_self Ideal.IsHomogeneous.toIdeal_homogeneousHull_eq_self

@[simp]
theorem HomogeneousIdeal.homogeneousHull_toIdeal_eq_self (I : HomogeneousIdeal 𝒜) :
    I.toIdeal.homogeneousHull 𝒜 = I :=
  HomogeneousIdeal.toIdeal_injective <| I.Homogeneous.toIdeal_homogeneousHull_eq_self
#align homogeneous_ideal.homogeneous_hull_to_ideal_eq_self HomogeneousIdeal.homogeneousHull_toIdeal_eq_self

variable (I 𝒜)

theorem Ideal.toIdeal_homogeneousHull_eq_supᵢ :
    (I.homogeneousHull 𝒜).toIdeal = ⨆ i, Ideal.span (GradedRing.proj 𝒜 i '' I) :=
  by
  rw [← Ideal.span_unionᵢ]
  apply congr_arg Ideal.span _
  ext1
  simp only [Set.mem_unionᵢ, Set.mem_image, mem_set_of_eq, GradedRing.proj_apply, SetLike.exists,
    exists_prop, Subtype.coe_mk, SetLike.mem_coe]
#align ideal.to_ideal_homogeneous_hull_eq_supr Ideal.toIdeal_homogeneousHull_eq_supᵢ

theorem Ideal.homogeneousHull_eq_supᵢ :
    I.homogeneousHull 𝒜 =
      ⨆ i,
        ⟨Ideal.span (GradedRing.proj 𝒜 i '' I),
          Ideal.isHomogeneousSpan 𝒜 _
            (by
              rintro _ ⟨x, -, rfl⟩
              apply SetLike.homogeneous_coe)⟩ :=
  by
  ext1
  rw [Ideal.toIdeal_homogeneousHull_eq_supᵢ, to_ideal_supr]
  rfl
#align ideal.homogeneous_hull_eq_supr Ideal.homogeneousHull_eq_supᵢ

end HomogeneousHull

section GaloisConnection

open HomogeneousIdeal

variable [Semiring A] [DecidableEq ι] [AddMonoid ι]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ) [GradedRing 𝒜]

include A

theorem Ideal.homogeneousHull.gc : GaloisConnection (Ideal.homogeneousHull 𝒜) toIdeal := fun I J =>
  ⟨le_trans (Ideal.le_toIdeal_homogeneousHull _ _), fun H =>
    J.homogeneousHull_toIdeal_eq_self ▸ Ideal.homogeneousHull_mono 𝒜 H⟩
#align ideal.homogeneous_hull.gc Ideal.homogeneousHull.gc

/-- `ideal.homogeneous_hull 𝒜` and `to_ideal : homogeneous_ideal 𝒜 → ideal A` form a galois
insertion-/
def Ideal.homogeneousHull.gi : GaloisInsertion (Ideal.homogeneousHull 𝒜) toIdeal
    where
  choice I H := ⟨I, le_antisymm H (I.le_toIdeal_homogeneousHull 𝒜) ▸ isHomogeneous _⟩
  gc := Ideal.homogeneousHull.gc 𝒜
  le_l_u I := Ideal.le_toIdeal_homogeneousHull _ _
  choice_eq I H := le_antisymm (I.le_toIdeal_homogeneousHull 𝒜) H
#align ideal.homogeneous_hull.gi Ideal.homogeneousHull.gi

theorem Ideal.homogeneousHull_eq_infₛ (I : Ideal A) :
    Ideal.homogeneousHull 𝒜 I = infₛ { J : HomogeneousIdeal 𝒜 | I ≤ J.toIdeal } :=
  Eq.symm <| IsGLB.infₛ_eq <| (Ideal.homogeneousHull.gc 𝒜).isLeast_l.IsGLB
#align ideal.homogeneous_hull_eq_Inf Ideal.homogeneousHull_eq_infₛ

end GaloisConnection

section IrrelevantIdeal

variable [Semiring A]

variable [DecidableEq ι]

variable [CanonicallyOrderedAddMonoid ι]

variable [SetLike σ A] [AddSubmonoidClass σ A] (𝒜 : ι → σ) [GradedRing 𝒜]

include A

open GradedRing SetLike.GradedMonoid DirectSum

/-- For a graded ring `⨁ᵢ 𝒜ᵢ` graded by a `canonically_ordered_add_monoid ι`, the irrelevant ideal
refers to `⨁_{i>0} 𝒜ᵢ`, or equivalently `{a | a₀ = 0}`. This definition is used in `Proj`
construction where `ι` is always `ℕ` so the irrelevant ideal is simply elements with `0` as
0-th coordinate.

# Future work
Here in the definition, `ι` is assumed to be `canonically_ordered_add_monoid`. However, the notion
of irrelevant ideal makes sense in a more general setting by defining it as the ideal of elements
with `0` as i-th coordinate for all `i ≤ 0`, i.e. `{a | ∀ (i : ι), i ≤ 0 → aᵢ = 0}`.
-/
def HomogeneousIdeal.irrelevant : HomogeneousIdeal 𝒜 :=
  ⟨(GradedRing.projZeroRingHom 𝒜).ker, fun i r (hr : (decompose 𝒜 r 0 : A) = 0) =>
    by
    change (decompose 𝒜 (decompose 𝒜 r _ : A) 0 : A) = 0
    by_cases h : i = 0
    · rw [h, hr, decompose_zero, zero_apply, ZeroMemClass.coe_zero]
    · rw [decompose_of_mem_ne 𝒜 (SetLike.coe_mem _) h]⟩
#align homogeneous_ideal.irrelevant HomogeneousIdeal.irrelevant

@[simp]
theorem HomogeneousIdeal.mem_irrelevant_iff (a : A) :
    a ∈ HomogeneousIdeal.irrelevant 𝒜 ↔ proj 𝒜 0 a = 0 :=
  Iff.rfl
#align homogeneous_ideal.mem_irrelevant_iff HomogeneousIdeal.mem_irrelevant_iff

@[simp]
theorem HomogeneousIdeal.toIdeal_irrelevant :
    (HomogeneousIdeal.irrelevant 𝒜).toIdeal = (GradedRing.projZeroRingHom 𝒜).ker :=
  rfl
#align homogeneous_ideal.to_ideal_irrelevant HomogeneousIdeal.toIdeal_irrelevant

end IrrelevantIdeal