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

! This file was ported from Lean 3 source module algebra.monoid_algebra.division
! leanprover-community/mathlib commit 72c366d0475675f1309d3027d3d7d47ee4423951
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.MonoidAlgebra.Basic
import Mathbin.Data.Finsupp.Order

/-!
# Division of `add_monoid_algebra` by monomials

This file is most important for when `G = ℕ` (polynomials) or `G = σ →₀ ℕ` (multivariate
polynomials).

In order to apply in maximal generality (such as for `laurent_polynomial`s), this uses
`∃ d, g' = g + d` in many places instead of `g ≤ g'`.

## Main definitions

* `add_monoid_algebra.div_of x g`: divides `x` by the monomial `add_monoid_algebra.of k G g`
* `add_monoid_algebra.mod_of x g`: the remainder upon dividing `x` by the monomial
  `add_monoid_algebra.of k G g`.

## Main results

* `add_monoid_algebra.div_of_add_mod_of`, `add_monoid_algebra.mod_of_add_div_of`: `div_of` and
  `mod_of` are well-behaved as quotient and remainder operators.

## Implementation notes

`∃ d, g' = g + d` is used as opposed to some other permutation up to commutativity in order to match
the definition of `semigroup_has_dvd`. The results in this file could be duplicated for
`monoid_algebra` by using `g ∣ g'`, but this can't be done automatically, and in any case is not
likely to be very useful.

-/

variable {k G : Type _} [Semiring k]

namespace AddMonoidAlgebra

section

variable [AddCancelCommMonoid G]

#print AddMonoidAlgebra.divOf /-
/-- Divide by `of' k G g`, discarding terms not divisible by this. -/
noncomputable def divOf (x : AddMonoidAlgebra k G) (g : G) : AddMonoidAlgebra k G :=
  -- note: comapping by `+ g` has the effect of subtracting `g` from every element in the support, and
    -- discarding the elements of the support from which `g` can't be subtracted. If `G` is an additive
    -- group, such as `ℤ` when used for `laurent_polynomial`, then no discarding occurs.
    @Finsupp.comapDomain.addMonoidHom
    _ _ _ _ ((· + ·) g) (add_right_injective g) x
#align add_monoid_algebra.div_of AddMonoidAlgebra.divOf
-/

-- mathport name: «expr /ᵒᶠ »
local infixl:70 " /ᵒᶠ " => divOf

/- warning: add_monoid_algebra.div_of_apply -> AddMonoidAlgebra.divOf_apply is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (g : G) (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g' : G), Eq.{succ u1} k (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x g) g') (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) x (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g g'))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (g : G) (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g' : G), Eq.{succ u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x g) g') (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) x (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g g'))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.div_of_apply AddMonoidAlgebra.divOf_applyₓ'. -/
@[simp]
theorem divOf_apply (g : G) (x : AddMonoidAlgebra k G) (g' : G) : (x /ᵒᶠ g) g' = x (g + g') :=
  rfl
#align add_monoid_algebra.div_of_apply AddMonoidAlgebra.divOf_apply

/- warning: add_monoid_algebra.support_div_of -> AddMonoidAlgebra.support_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (g : G) (x : AddMonoidAlgebra.{u1, u2} k G _inst_1), Eq.{succ u2} (Finset.{u2} G) (Finsupp.support.{u2, u1} G k (MulZeroClass.toHasZero.{u1} k (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} k (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} k (Semiring.toNonAssocSemiring.{u1} k _inst_1)))) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x g)) (Finset.preimage.{u2, u2} G G (Finsupp.support.{u2, u1} G k (MulZeroClass.toHasZero.{u1} k (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} k (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} k (Semiring.toNonAssocSemiring.{u1} k _inst_1)))) x) (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g) (Function.Injective.injOn.{u2, u2} G G (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g) (add_right_injective.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))) (AddLeftCancelSemigroup.toIsLeftCancelAdd.{u2} G (AddLeftCancelMonoid.toAddLeftCancelSemigroup.{u2} G (AddCancelCommMonoid.toAddLeftCancelMonoid.{u2} G _inst_2))) g) (Set.preimage.{u2, u2} G G (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} G) (Set.{u2} G) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} G) (Set.{u2} G) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} G) (Set.{u2} G) (Finset.Set.hasCoeT.{u2} G))) (Finsupp.support.{u2, u1} G k (MulZeroClass.toHasZero.{u1} k (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} k (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} k (Semiring.toNonAssocSemiring.{u1} k _inst_1)))) x)))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (g : G) (x : AddMonoidAlgebra.{u2, u1} k G _inst_1), Eq.{succ u1} (Finset.{u1} G) (Finsupp.support.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1)) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x g)) (Finset.preimage.{u1, u1} G G (Finsupp.support.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1)) x) ((fun (x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.821 : G) (x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.823 : G) => HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.821 x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.823) g) (Function.Injective.injOn.{u1, u1} G G ((fun (x._@.Mathlib.Algebra.Group.Defs._hyg.2622 : G) (x._@.Mathlib.Algebra.Group.Defs._hyg.2624 : G) => HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) x._@.Mathlib.Algebra.Group.Defs._hyg.2622 x._@.Mathlib.Algebra.Group.Defs._hyg.2624) g) (add_right_injective.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))) (IsCancelAdd.toIsLeftCancelAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))) (AddCancelMonoid.toIsCancelAdd.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))) g) (Set.preimage.{u1, u1} G G ((fun (x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.821 : G) (x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.823 : G) => HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.821 x._@.Mathlib.Algebra.MonoidAlgebra.Division._hyg.823) g) (Finset.toSet.{u1} G (Finsupp.support.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1)) x)))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.support_div_of AddMonoidAlgebra.support_divOfₓ'. -/
@[simp]
theorem support_divOf (g : G) (x : AddMonoidAlgebra k G) :
    (x /ᵒᶠ g).support =
      x.support.Preimage ((· + ·) g) (Function.Injective.injOn (add_right_injective g) _) :=
  rfl
#align add_monoid_algebra.support_div_of AddMonoidAlgebra.support_divOf

/- warning: add_monoid_algebra.zero_div_of -> AddMonoidAlgebra.zero_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (Zero.zero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (MulZeroClass.toHasZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toMulZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))))) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (Zero.zero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (MulZeroClass.toHasZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toMulZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 0 (Zero.toOfNat0.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (MonoidWithZero.toZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Semiring.toMonoidWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.semiring.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))))) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 0 (Zero.toOfNat0.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (MonoidWithZero.toZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Semiring.toMonoidWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.semiring.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.zero_div_of AddMonoidAlgebra.zero_divOfₓ'. -/
@[simp]
theorem zero_divOf (g : G) : (0 : AddMonoidAlgebra k G) /ᵒᶠ g = 0 :=
  map_zero _
#align add_monoid_algebra.zero_div_of AddMonoidAlgebra.zero_divOf

/- warning: add_monoid_algebra.div_of_zero -> AddMonoidAlgebra.divOf_zero is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x (OfNat.ofNat.{u2} G 0 (OfNat.mk.{u2} G 0 (Zero.zero.{u2} G (AddZeroClass.toHasZero.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))) x
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x (OfNat.ofNat.{u1} G 0 (Zero.toOfNat0.{u1} G (AddRightCancelMonoid.toZero.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) x
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.div_of_zero AddMonoidAlgebra.divOf_zeroₓ'. -/
@[simp]
theorem divOf_zero (x : AddMonoidAlgebra k G) : x /ᵒᶠ 0 = x :=
  by
  ext
  simp only [AddMonoidAlgebra.divOf_apply, zero_add]
#align add_monoid_algebra.div_of_zero AddMonoidAlgebra.divOf_zero

/- warning: add_monoid_algebra.add_div_of -> AddMonoidAlgebra.add_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (y : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (Distrib.toHasAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))) x y) g) (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (Distrib.toHasAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x g) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 y g))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (y : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Distrib.toAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))) x y) g) (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Distrib.toAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x g) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 y g))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.add_div_of AddMonoidAlgebra.add_divOfₓ'. -/
theorem add_divOf (x y : AddMonoidAlgebra k G) (g : G) : (x + y) /ᵒᶠ g = x /ᵒᶠ g + y /ᵒᶠ g :=
  map_add _ _ _
#align add_monoid_algebra.add_div_of AddMonoidAlgebra.add_divOf

/- warning: add_monoid_algebra.div_of_add -> AddMonoidAlgebra.divOf_add is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (a : G) (b : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) a b)) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x a) b)
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (a : G) (b : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) a b)) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x a) b)
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.div_of_add AddMonoidAlgebra.divOf_addₓ'. -/
theorem divOf_add (x : AddMonoidAlgebra k G) (a b : G) : x /ᵒᶠ (a + b) = x /ᵒᶠ a /ᵒᶠ b :=
  by
  ext
  simp only [AddMonoidAlgebra.divOf_apply, add_assoc]
#align add_monoid_algebra.div_of_add AddMonoidAlgebra.divOf_add

/- warning: add_monoid_algebra.div_of_hom -> AddMonoidAlgebra.divOfHom is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G], MonoidHom.{u2, max u2 u1} (Multiplicative.{u2} G) (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (Multiplicative.mulOneClass.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))) (MulZeroOneClass.toMulOneClass.{max u2 u1} (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (NonAssocSemiring.toMulZeroOneClass.{max u2 u1} (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (Semiring.toNonAssocSemiring.{max u2 u1} (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (AddMonoid.End.semiring.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.addCommMonoid.{u2, u1} k G _inst_1)))))
but is expected to have type
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G], MonoidHom.{u2, max u2 u1} (Multiplicative.{u2} G) (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (Multiplicative.mulOneClass.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))) (MulZeroOneClass.toMulOneClass.{max u1 u2} (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (NonAssocSemiring.toMulZeroOneClass.{max u1 u2} (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (Semiring.toNonAssocSemiring.{max u1 u2} (AddMonoid.End.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoid.toAddZeroClass.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidWithOne.toAddMonoid.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddCommMonoidWithOne.toAddMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonAssocSemiring.toAddCommMonoidWithOne.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonAssocSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))) (AddMonoid.End.semiring.{max u1 u2} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.addCommMonoid.{u1, u2} k G _inst_1)))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.div_of_hom AddMonoidAlgebra.divOfHomₓ'. -/
/-- A bundled version of `add_monoid_algebra.div_of`. -/
@[simps]
noncomputable def divOfHom : Multiplicative G →* AddMonoid.End (AddMonoidAlgebra k G)
    where
  toFun g :=
    { toFun := fun x => divOf x g.toAdd
      map_zero' := zero_divOf _
      map_add' := fun x y => add_divOf x y g.toAdd }
  map_one' := AddMonoidHom.ext divOf_zero
  map_mul' g₁ g₂ :=
    AddMonoidHom.ext fun x => (congr_arg _ (add_comm g₁.toAdd g₂.toAdd)).trans (divOf_add _ _ _)
#align add_monoid_algebra.div_of_hom AddMonoidAlgebra.divOfHom

/- warning: add_monoid_algebra.of'_mul_div_of -> AddMonoidAlgebra.of'_mul_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (a : G) (x : AddMonoidAlgebra.{u1, u2} k G _inst_1), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.hasMul.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))) (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 a) x) a) x
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (a : G) (x : AddMonoidAlgebra.{u2, u1} k G _inst_1), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.hasMul.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))) (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 a) x) a) x
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.of'_mul_div_of AddMonoidAlgebra.of'_mul_divOfₓ'. -/
theorem of'_mul_divOf (a : G) (x : AddMonoidAlgebra k G) : of' k G a * x /ᵒᶠ a = x :=
  by
  ext b
  rw [AddMonoidAlgebra.divOf_apply, of'_apply, single_mul_apply_aux, one_mul]
  intro c
  exact add_right_inj _
#align add_monoid_algebra.of'_mul_div_of AddMonoidAlgebra.of'_mul_divOf

/- warning: add_monoid_algebra.mul_of'_div_of -> AddMonoidAlgebra.mul_of'_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (a : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.hasMul.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))) x (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 a)) a) x
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (a : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.hasMul.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))) x (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 a)) a) x
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mul_of'_div_of AddMonoidAlgebra.mul_of'_divOfₓ'. -/
theorem mul_of'_divOf (x : AddMonoidAlgebra k G) (a : G) : x * of' k G a /ᵒᶠ a = x :=
  by
  ext b
  rw [AddMonoidAlgebra.divOf_apply, of'_apply, mul_single_apply_aux, mul_one]
  intro c
  rw [add_comm]
  exact add_right_inj _
#align add_monoid_algebra.mul_of'_div_of AddMonoidAlgebra.mul_of'_divOf

/- warning: add_monoid_algebra.of'_div_of -> AddMonoidAlgebra.of'_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (a : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 a) a) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 1 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 1 (One.one.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.one.{u1, u2} k G _inst_1 (AddZeroClass.toHasZero.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (a : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 a) a) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 1 (One.toOfNat1.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.one.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toZero.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.of'_div_of AddMonoidAlgebra.of'_divOfₓ'. -/
theorem of'_divOf (a : G) : of' k G a /ᵒᶠ a = 1 := by
  simpa only [one_mul] using mul_of'_div_of (1 : AddMonoidAlgebra k G) a
#align add_monoid_algebra.of'_div_of AddMonoidAlgebra.of'_divOf

#print AddMonoidAlgebra.modOf /-
/-- The remainder upon division by `of' k G g`. -/
noncomputable def modOf (x : AddMonoidAlgebra k G) (g : G) : AddMonoidAlgebra k G :=
  x.filterₓ fun g₁ => ¬∃ g₂, g₁ = g + g₂
#align add_monoid_algebra.mod_of AddMonoidAlgebra.modOf
-/

-- mathport name: «expr %ᵒᶠ »
local infixl:70 " %ᵒᶠ " => modOf

/- warning: add_monoid_algebra.mod_of_apply_of_not_exists_add -> AddMonoidAlgebra.modOf_apply_of_not_exists_add is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G) (g' : G), (Not (Exists.{succ u2} G (fun (d : G) => Eq.{succ u2} G g' (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g d)))) -> (Eq.{succ u1} k (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g) g') (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) x g'))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G) (g' : G), (Not (Exists.{succ u1} G (fun (d : G) => Eq.{succ u1} G g' (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)))) -> (Eq.{succ u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g) g') (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) x g'))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mod_of_apply_of_not_exists_add AddMonoidAlgebra.modOf_apply_of_not_exists_addₓ'. -/
@[simp]
theorem modOf_apply_of_not_exists_add (x : AddMonoidAlgebra k G) (g : G) (g' : G)
    (h : ¬∃ d, g' = g + d) : (x %ᵒᶠ g) g' = x g' :=
  Finsupp.filter_apply_pos _ _ h
#align add_monoid_algebra.mod_of_apply_of_not_exists_add AddMonoidAlgebra.modOf_apply_of_not_exists_add

/- warning: add_monoid_algebra.mod_of_apply_of_exists_add -> AddMonoidAlgebra.modOf_apply_of_exists_add is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G) (g' : G), (Exists.{succ u2} G (fun (d : G) => Eq.{succ u2} G g' (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g d))) -> (Eq.{succ u1} k (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g) g') (OfNat.ofNat.{u1} k 0 (OfNat.mk.{u1} k 0 (Zero.zero.{u1} k (MulZeroClass.toHasZero.{u1} k (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} k (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} k (Semiring.toNonAssocSemiring.{u1} k _inst_1))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G) (g' : G), (Exists.{succ u1} G (fun (d : G) => Eq.{succ u1} G g' (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d))) -> (Eq.{succ u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g) g') (OfNat.ofNat.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') 0 (Zero.toOfNat0.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') (MonoidWithZero.toZero.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') (Semiring.toMonoidWithZero.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) g') _inst_1)))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mod_of_apply_of_exists_add AddMonoidAlgebra.modOf_apply_of_exists_addₓ'. -/
@[simp]
theorem modOf_apply_of_exists_add (x : AddMonoidAlgebra k G) (g : G) (g' : G)
    (h : ∃ d, g' = g + d) : (x %ᵒᶠ g) g' = 0 :=
  Finsupp.filter_apply_neg _ _ <| by rwa [Classical.not_not]
#align add_monoid_algebra.mod_of_apply_of_exists_add AddMonoidAlgebra.modOf_apply_of_exists_add

/- warning: add_monoid_algebra.mod_of_apply_add_self -> AddMonoidAlgebra.modOf_apply_add_self is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G) (d : G), Eq.{succ u1} k (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g) (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) d g)) (OfNat.ofNat.{u1} k 0 (OfNat.mk.{u1} k 0 (Zero.zero.{u1} k (MulZeroClass.toHasZero.{u1} k (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} k (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} k (Semiring.toNonAssocSemiring.{u1} k _inst_1)))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G) (d : G), Eq.{succ u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) d g)) (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) d g)) (OfNat.ofNat.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) d g)) 0 (Zero.toOfNat0.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) d g)) (MonoidWithZero.toZero.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) d g)) (Semiring.toMonoidWithZero.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) d g)) _inst_1))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mod_of_apply_add_self AddMonoidAlgebra.modOf_apply_add_selfₓ'. -/
@[simp]
theorem modOf_apply_add_self (x : AddMonoidAlgebra k G) (g : G) (d : G) : (x %ᵒᶠ g) (d + g) = 0 :=
  modOf_apply_of_exists_add _ _ _ ⟨_, add_comm _ _⟩
#align add_monoid_algebra.mod_of_apply_add_self AddMonoidAlgebra.modOf_apply_add_self

/- warning: add_monoid_algebra.mod_of_apply_self_add -> AddMonoidAlgebra.modOf_apply_self_add is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G) (d : G), Eq.{succ u1} k (coeFn.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (fun (_x : AddMonoidAlgebra.{u1, u2} k G _inst_1) => G -> k) (AddMonoidAlgebra.coeFun.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g) (HAdd.hAdd.{u2, u2, u2} G G G (instHAdd.{u2} G (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))) g d)) (OfNat.ofNat.{u1} k 0 (OfNat.mk.{u1} k 0 (Zero.zero.{u1} k (MulZeroClass.toHasZero.{u1} k (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} k (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} k (Semiring.toNonAssocSemiring.{u1} k _inst_1)))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G) (d : G), Eq.{succ u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)) (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Finsupp.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) G (fun (_x : G) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) _x) (Finsupp.funLike.{u1, u2} G k (MonoidWithZero.toZero.{u2} k (Semiring.toMonoidWithZero.{u2} k _inst_1))) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)) (OfNat.ofNat.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)) 0 (Zero.toOfNat0.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)) (MonoidWithZero.toZero.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)) (Semiring.toMonoidWithZero.{u2} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : G) => k) (HAdd.hAdd.{u1, u1, u1} G G G (instHAdd.{u1} G (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))) g d)) _inst_1))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mod_of_apply_self_add AddMonoidAlgebra.modOf_apply_self_addₓ'. -/
@[simp]
theorem modOf_apply_self_add (x : AddMonoidAlgebra k G) (g : G) (d : G) : (x %ᵒᶠ g) (g + d) = 0 :=
  modOf_apply_of_exists_add _ _ _ ⟨_, rfl⟩
#align add_monoid_algebra.mod_of_apply_self_add AddMonoidAlgebra.modOf_apply_self_add

/- warning: add_monoid_algebra.of'_mul_mod_of -> AddMonoidAlgebra.of'_mul_modOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (g : G) (x : AddMonoidAlgebra.{u1, u2} k G _inst_1), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.hasMul.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))) (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 g) x) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (Zero.zero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (MulZeroClass.toHasZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toMulZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (g : G) (x : AddMonoidAlgebra.{u2, u1} k G _inst_1), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.hasMul.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))) (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 g) x) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 0 (Zero.toOfNat0.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (MonoidWithZero.toZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Semiring.toMonoidWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.semiring.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.of'_mul_mod_of AddMonoidAlgebra.of'_mul_modOfₓ'. -/
theorem of'_mul_modOf (g : G) (x : AddMonoidAlgebra k G) : of' k G g * x %ᵒᶠ g = 0 :=
  by
  ext g'
  rw [Finsupp.zero_apply]
  obtain ⟨d, rfl⟩ | h := em (∃ d, g' = g + d)
  · rw [mod_of_apply_self_add]
  · rw [mod_of_apply_of_not_exists_add _ _ _ h, of'_apply, single_mul_apply_of_not_exists_add _ _ h]
#align add_monoid_algebra.of'_mul_mod_of AddMonoidAlgebra.of'_mul_modOf

/- warning: add_monoid_algebra.mul_of'_mod_of -> AddMonoidAlgebra.mul_of'_modOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.hasMul.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))) x (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 g)) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (Zero.zero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (MulZeroClass.toHasZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toMulZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.hasMul.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))) x (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 g)) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 0 (Zero.toOfNat0.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (MonoidWithZero.toZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Semiring.toMonoidWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.semiring.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mul_of'_mod_of AddMonoidAlgebra.mul_of'_modOfₓ'. -/
theorem mul_of'_modOf (x : AddMonoidAlgebra k G) (g : G) : x * of' k G g %ᵒᶠ g = 0 :=
  by
  ext g'
  rw [Finsupp.zero_apply]
  obtain ⟨d, rfl⟩ | h := em (∃ d, g' = g + d)
  · rw [mod_of_apply_self_add]
  · rw [mod_of_apply_of_not_exists_add _ _ _ h, of'_apply, mul_single_apply_of_not_exists_add]
    simpa only [add_comm] using h
#align add_monoid_algebra.mul_of'_mod_of AddMonoidAlgebra.mul_of'_modOf

/- warning: add_monoid_algebra.of'_mod_of -> AddMonoidAlgebra.of'_modOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 g) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (Zero.zero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (MulZeroClass.toHasZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toMulZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 g) g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 0 (Zero.toOfNat0.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (MonoidWithZero.toZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Semiring.toMonoidWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.semiring.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.of'_mod_of AddMonoidAlgebra.of'_modOfₓ'. -/
theorem of'_modOf (g : G) : of' k G g %ᵒᶠ g = 0 := by
  simpa only [one_mul] using mul_of'_mod_of (1 : AddMonoidAlgebra k G) g
#align add_monoid_algebra.of'_mod_of AddMonoidAlgebra.of'_modOf

/- warning: add_monoid_algebra.div_of_add_mod_of -> AddMonoidAlgebra.divOf_add_modOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G), Eq.{succ (max u2 u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (Distrib.toHasAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))) (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.hasMul.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))) (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 g) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x g)) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g)) x
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Distrib.toAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))) (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.hasMul.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))) (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 g) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x g)) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g)) x
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.div_of_add_mod_of AddMonoidAlgebra.divOf_add_modOfₓ'. -/
theorem divOf_add_modOf (x : AddMonoidAlgebra k G) (g : G) : of' k G g * (x /ᵒᶠ g) + x %ᵒᶠ g = x :=
  by
  ext g'
  simp_rw [Finsupp.add_apply]
  obtain ⟨d, rfl⟩ | h := em (∃ d, g' = g + d)
  swap
  ·
    rw [mod_of_apply_of_not_exists_add _ _ _ h, of'_apply, single_mul_apply_of_not_exists_add _ _ h,
      zero_add]
  · rw [mod_of_apply_self_add, add_zero]
    rw [of'_apply, single_mul_apply_aux _ _ _, one_mul, div_of_apply]
    intro a
    exact add_right_inj _
#align add_monoid_algebra.div_of_add_mod_of AddMonoidAlgebra.divOf_add_modOf

/- warning: add_monoid_algebra.mod_of_add_div_of -> AddMonoidAlgebra.modOf_add_divOf is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] (x : AddMonoidAlgebra.{u1, u2} k G _inst_1) (g : G), Eq.{succ (max u2 u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (Distrib.toHasAdd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g) (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.{u1, u2} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.hasMul.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))) (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 g) (AddMonoidAlgebra.divOf.{u1, u2} k G _inst_1 _inst_2 x g))) x
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] (x : AddMonoidAlgebra.{u2, u1} k G _inst_1) (g : G), Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (HAdd.hAdd.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Distrib.toAdd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (NonUnitalNonAssocSemiring.toDistrib.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))))) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g) (HMul.hMul.{max u2 u1, max u2 u1, max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.{u2, u1} k G _inst_1) (instHMul.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.hasMul.{u2, u1} k G _inst_1 (AddZeroClass.toAdd.{u1} G (AddMonoid.toAddZeroClass.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2))))))) (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 g) (AddMonoidAlgebra.divOf.{u2, u1} k G _inst_1 _inst_2 x g))) x
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.mod_of_add_div_of AddMonoidAlgebra.modOf_add_divOfₓ'. -/
theorem modOf_add_divOf (x : AddMonoidAlgebra k G) (g : G) : x %ᵒᶠ g + of' k G g * (x /ᵒᶠ g) = x :=
  by rw [add_comm, div_of_add_mod_of]
#align add_monoid_algebra.mod_of_add_div_of AddMonoidAlgebra.modOf_add_divOf

/- warning: add_monoid_algebra.of'_dvd_iff_mod_of_eq_zero -> AddMonoidAlgebra.of'_dvd_iff_modOf_eq_zero is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {G : Type.{u2}} [_inst_1 : Semiring.{u1} k] [_inst_2 : AddCancelCommMonoid.{u2} G] {x : AddMonoidAlgebra.{u1, u2} k G _inst_1} {g : G}, Iff (Dvd.Dvd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (semigroupDvd.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (SemigroupWithZero.toSemigroup.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalSemiring.toSemigroupWithZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalSemiring.{u1, u2} k G _inst_1 (AddMonoid.toAddSemigroup.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2)))))))) (AddMonoidAlgebra.of'.{u1, u2} k G _inst_1 g) x) (Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.modOf.{u1, u2} k G _inst_1 _inst_2 x g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (OfNat.mk.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) 0 (Zero.zero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (MulZeroClass.toHasZero.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (NonUnitalNonAssocSemiring.toMulZeroClass.{max u2 u1} (AddMonoidAlgebra.{u1, u2} k G _inst_1) (AddMonoidAlgebra.nonUnitalNonAssocSemiring.{u1, u2} k G _inst_1 (AddZeroClass.toHasAdd.{u2} G (AddMonoid.toAddZeroClass.{u2} G (AddRightCancelMonoid.toAddMonoid.{u2} G (AddCancelMonoid.toAddRightCancelMonoid.{u2} G (AddCancelCommMonoid.toAddCancelMonoid.{u2} G _inst_2))))))))))))
but is expected to have type
  forall {k : Type.{u2}} {G : Type.{u1}} [_inst_1 : Semiring.{u2} k] [_inst_2 : AddCancelCommMonoid.{u1} G] {x : AddMonoidAlgebra.{u2, u1} k G _inst_1} {g : G}, Iff (Dvd.dvd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (semigroupDvd.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (SemigroupWithZero.toSemigroup.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (NonUnitalSemiring.toSemigroupWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.nonUnitalSemiring.{u2, u1} k G _inst_1 (AddMonoid.toAddSemigroup.{u1} G (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))))) (AddMonoidAlgebra.of'.{u2, u1} k G _inst_1 g) x) (Eq.{max (succ u2) (succ u1)} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.modOf.{u2, u1} k G _inst_1 _inst_2 x g) (OfNat.ofNat.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) 0 (Zero.toOfNat0.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (MonoidWithZero.toZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (Semiring.toMonoidWithZero.{max u2 u1} (AddMonoidAlgebra.{u2, u1} k G _inst_1) (AddMonoidAlgebra.semiring.{u2, u1} k G _inst_1 (AddRightCancelMonoid.toAddMonoid.{u1} G (AddCancelMonoid.toAddRightCancelMonoid.{u1} G (AddCancelCommMonoid.toAddCancelMonoid.{u1} G _inst_2)))))))))
Case conversion may be inaccurate. Consider using '#align add_monoid_algebra.of'_dvd_iff_mod_of_eq_zero AddMonoidAlgebra.of'_dvd_iff_modOf_eq_zeroₓ'. -/
theorem of'_dvd_iff_modOf_eq_zero {x : AddMonoidAlgebra k G} {g : G} :
    of' k G g ∣ x ↔ x %ᵒᶠ g = 0 := by
  constructor
  · rintro ⟨x, rfl⟩
    rw [of'_mul_mod_of]
  · intro h
    rw [← div_of_add_mod_of x g, h, add_zero]
    exact dvd_mul_right _ _
#align add_monoid_algebra.of'_dvd_iff_mod_of_eq_zero AddMonoidAlgebra.of'_dvd_iff_modOf_eq_zero

end

end AddMonoidAlgebra


import order.complete_lattice
import set_theory.ordinal
import data.nat.prime

universes u v

variables (A : Type u) (B : Type v) [partial_order A] [partial_order B]

/-- Aiming to construct a pscompletion of `B` that preserves all sups in `A`.
  So if we have a partial order `C` a monotone function `B -> C` and a `sup_hom`
  from `A -> C` that commute with `f` there is a unique cocontinuous map from
  the pscompletion to `C` such that everything commutes. -/

def presheaf : Type* :=
{ s : B → Prop // ∀ a b, a ≤ b → s b → s a }

variables {A B}

namespace presheaf

instance : has_coe_to_fun (presheaf B) (λ _, B → Prop) :=
⟨subtype.val⟩

@[simp] lemma coe_mk (s : B → Prop) (hs : ∀ a b, a ≤ b → s b → s a) :
  @coe_fn (presheaf B) _ _ (⟨s, hs⟩ : presheaf B) = s := rfl

instance : partial_order (presheaf B) :=
{ le := λ a b, ∀ x, a x → b x,
  le_trans := λ a b c hab hbc x hax, hbc _ (hab _ hax),
  le_refl := λ _ _, id,
  le_antisymm := λ a b hab hba, subtype.val_injective (funext $ λ x, propext ⟨hab _, hba _⟩) }

lemma le_def {a b : presheaf B} : a ≤ b = ∀ x, a x → b x := rfl

instance : has_Inf (presheaf B) :=
{ Inf := λ s, ⟨λ p, ∀ B : presheaf B, B ∈ s → B p,
     λ a b hab h B hBs, B.2 _ _ hab (h _ hBs)⟩ }

instance : complete_lattice (presheaf B) :=
complete_lattice_of_Inf _
  (λ s, begin
    split,
    { dsimp [Inf, lower_bounds],
      intros B hBs p h,
      apply h,
      exact hBs },
    { dsimp [Inf, upper_bounds, lower_bounds],
      intros B h p hBp B hBs,
      apply h,
      exact hBs,
      exact hBp }
  end)

lemma infi_def {ι : Sort*} (a : ι → presheaf B) :
  infi a = ⟨λ p, ∀ i, a i p, λ x y hxy h i, (a i).2 _ y hxy (h i)⟩ :=
le_antisymm
  (infi_le_iff.2 (λ B h p hBp i, h i _ hBp))
  (le_infi (λ i p h, h _))

lemma supr_def {ι : Sort*} (a : ι → presheaf B) :
  supr a = ⟨λ p, ∃ i, a i p, λ x y hxy ⟨i, hi⟩, ⟨i, (a i).2 x y hxy hi⟩⟩ :=
le_antisymm
  (supr_le_iff.2 (λ i p h, ⟨i, h⟩))
  (le_supr_iff.2 (λ B h p ⟨i, hi⟩, h i _ hi))

def yoneda (a : B) : presheaf B :=
⟨λ b, b ≤ a, λ b c, le_trans⟩

def yoneda_le_iff (a : presheaf B) (p : B) : yoneda p ≤ a ↔ a p :=
begin
  simp [yoneda, presheaf.le_def],
  split,
  { intro h, apply h, exact le_rfl },
  { intros h x hxp,
    apply a.2,
    apply hxp,
    exact h }
end

lemma yoneda_mono {a b : B} : yoneda a ≤ yoneda b ↔ a ≤ b :=
begin
  rw yoneda_le_iff, refl,
end

lemma eq_supr (a : presheaf B) : a = ⨆ (p : B) (h : a p), yoneda p :=
begin
  apply le_antisymm; simp only [le_supr_iff, supr_le_iff, yoneda_le_iff],
  { intros B hB p,
    exact hB p },
  { exact λ _, id }
end

def extend {B : Type*} [complete_lattice B] (f : A → B) : presheaf A → B :=
λ a, ⨆ (p : A) (h : a p), f p

lemma extend_yoneda {B : Type*} [complete_lattice B] (f : A → B) (a : A)
  (hf : monotone f) : extend f (yoneda a) = f a :=
begin
  dsimp [extend, yoneda],
  apply le_antisymm,
  { refine supr_le (λ b, supr_le (λ h, hf h)) },
  { refine le_supr_iff.2 (λ b hb, _),
    refine le_trans _ (hb a),
    refine le_supr_iff.2 (λ b hb, hb le_rfl) }
end

lemma extend_supr {B : Type*} {ι : Sort*} [complete_lattice B] (f : A → B) (a : ι → presheaf A) :
  extend f (supr a) = ⨆ i, extend f (a i) :=
begin
  dsimp [extend],
  apply le_antisymm;
  simp only [le_supr_iff, supr_le_iff, presheaf.supr_def];
  dsimp;
  simp only [exists_imp_distrib],
  { intros b i hbi c h,
    exact h _ _ hbi },
  { intros i b hbi c h,
    exact h _ _ hbi }
end

def total : presheaf (presheaf A) →o presheaf A :=
{ to_fun := λ F, ⟨λ X, F (yoneda X), begin
    intros B C hBC x,
    exact F.2 _ _ (yoneda_mono.2 hBC) x
  end⟩,
  monotone' := λ F G hFG a hF, hFG _ hF }

def map (f : A → B) : presheaf A → presheaf B :=
extend (λ a, yoneda (f a))

def map_total (f : A → B) (F : presheaf (presheaf A)) : map f (total F) = total (map (map f) F) :=
begin
  dsimp [map, extend, total],
  apply le_antisymm,
  { simp only [supr_le_iff, presheaf.supr_def, presheaf.le_def],
    simp,
    intros b a ha hb,
    use yoneda a,
    use ha,
    dsimp [yoneda, presheaf.le_def] at *,
    intros x hxb,
    use a,
    use le_rfl,
    use le_trans hxb hb },
  { simp only [le_supr_iff, presheaf.supr_def, presheaf.le_def],
    simp [yoneda],
    intros a b ha h,
    cases h le_rfl with x hx,
    use x,split,
    refine F.2 _ _ _ ha,
    simp [presheaf.le_def],
    intros y hy,
    exact b.2 _ _ hy hx.1,
    exact hx.2
     }

end

def comp (f : A →o B) : presheaf B → presheaf A :=
λ b, ⟨λ a, b (f a), λ x y hxy, b.2 _ _ $ f.monotone hxy⟩

example (f : A →o B) : galois_connection (map f) (comp f):=
begin
  intros x y,
  simp [map, comp, extend, supr_le_iff, presheaf.le_def, presheaf.supr_def, yoneda],
  split,
  { intros h a hxa, exact h _ _ hxa le_rfl },
  { intros h b a hxa hba,
    exact y.2 _ _ hba (h _ hxa) }
end

variables {A' : Type*} [complete_lattice A'] [B' : Type*] [complete_lattice B']
  (i : A → A') (j : B → B') (hi : monotone i) (hj : monotone j)
include hi hj

example (f : A → B) (hf : monotone f) (g : presheaf B → presheaf A)
  (h : galois_connection (map f) g)
  (f' : A' → B') (g' : B' → A') (gc : galois_connection f' g')
  (hfij : ∀ x, f' (i x) = j (f x)) :
  g' ∘ extend j = extend i ∘ g :=
-- have hg : g = (λ b, ⨆ (c : presheaf A) (h : map f c ≤ b), c),
--   begin
--     funext b,
--     apply le_antisymm,
--     { simp only [le_supr_iff, supr_le_iff],
--       intros c hc,
--       refine hc _ _,
--       exact h.l_u_le _ },
--     { refine supr_le (λ c, supr_le (λ hc, h.le_iff_le.1 hc)) },
--   end,
have hg : g = comp ⟨f, hf⟩ :=
  begin
    apply le_antisymm,
    intro x,
    swap,
    intro x,
    rw [← h.le_iff_le],
    simp [comp, map],
    intro a,
    simp [extend, yoneda, presheaf.supr_def],
    intros,
    apply x.2 _ (f x_1),
    assumption, assumption,
    simp [comp],
    intro a,
    intro h1,
    rw [← yoneda_le_iff, ← h.le_iff_le] at h1,
    simp [yoneda, map, extend] at *,
    apply h1,
    apply le_rfl,
    simp,

  end,
have hg' : g' = (λ b, ⨆ (c : A') (h : f' c ≤ b), c),
  begin
    funext b,
    apply le_antisymm,
    { simp only [le_supr_iff, supr_le_iff],
      intros c hc,
      refine hc _ _,
      exact gc.l_u_le _ },
    { refine supr_le (λ c, supr_le (λ hc, gc.le_iff_le.1 hc)) },
  end,
begin
  funext a,
  dsimp,
  substs g g',
  rw [eq_supr a],
  simp only [extend_supr, extend_yoneda _ _ hj],
  simp [extend, comp, presheaf.supr_def, yoneda],
  apply le_antisymm,
  { simp only [le_supr_iff, supr_le_iff],
    intros x hx y hy,
    refine le_trans (gc.le_iff_le.1 (hx ⊤ _)) _,
    { intros b hai,
      exact le_top,
       },
    simp only [supr_le_iff], admit,
     },
  { simp only [le_supr_iff, supr_le_iff],
    intros b c hbc x hx,
    apply hx,
    intros d hd,
    rw [hfij],
    apply hd,
    refine a.2 _ _ hbc.2 hbc.1 }
end

example (f : A → B) (hf : monotone f) (g : presheaf B → presheaf A)
  (h : galois_connection (map f) g)
  (f' : A' → B') (g' : B' → A') (gc : galois_connection f' g')
  (hfij : ∀ x, f' (i x) ≤ j (f x)) :
  extend i ∘ g ≤ g' ∘ extend j :=
have hg : g = comp ⟨f, hf⟩ := sorry,
have hg' : g' = (λ b, ⨆ (c : A') (h : f' c ≤ b), c),
  begin
    funext b,
    apply le_antisymm,
    { simp only [le_supr_iff, supr_le_iff],
      intros c hc,
      refine hc _ _,
      exact gc.l_u_le _ },
    { refine supr_le (λ c, supr_le (λ hc, gc.le_iff_le.1 hc)) },
  end,
begin
  intros a,
  dsimp,
  substs g g',
  simp only [extend_supr, extend_yoneda _ _ hj],
  simp [extend, comp, presheaf.supr_def, yoneda],
  { simp only [le_supr_iff, supr_le_iff],
    intros b hb x hx,
    apply hx,
    intros d hd,
    refine le_trans (hfij _) _,
    apply hd,
    exact hb }
end

example : false :=
begin
  have := @thing ℕ ℕ _ _,

end

example (f : A → B) (hf : monotone f) (g : presheaf B → presheaf A)
  (h : galois_connection g (map f))
  (f' : A' → B') (g' : B' → A') (gc : galois_connection g' f')
  (hfij : f' ∘ i = j ∘ f) :
  g' ∘ extend j = extend i ∘ g :=
-- have hg : g = (λ b, ⨆ (c : presheaf A) (h : map f c ≤ b), c),
--   begin
--     funext b,
--     apply le_antisymm,
--     { simp only [le_supr_iff, supr_le_iff],
--       intros c hc,
--       refine hc _ _,
--       exact h.l_u_le _ },
--     { refine supr_le (λ c, supr_le (λ hc, h.le_iff_le.1 hc)) },
--   end,
have hfij' : f' ∘ extend i = extend j ∘ map f :=
begin
  funext x,
  dsimp [extend, gc.l_supr],
end,
have hg : g = comp ⟨f, hf⟩ := sorry,
have hg' : g' = (λ b, ⨆ (c : A') (h : f' c ≤ b), c),
  begin
    funext b,
    apply le_antisymm,
    { simp only [le_supr_iff, supr_le_iff],
      intros c hc,
      refine hc _ _,
      exact gc'.l_u_le _ },
    { refine supr_le (λ c, supr_le (λ hc, gc.le_iff_le.1 hc)) },
  end,
begin
  funext a,
  dsimp,
  substs g g',
  rw [eq_supr a],
  simp only [extend_supr, extend_yoneda _ _ hj],
  simp [extend, comp, presheaf.supr_def, yoneda],
  apply le_antisymm,
  { simp only [le_supr_iff, supr_le_iff],
    intros x hx y hy, }

end

end presheaf

variable (B)

def copresheaf : Type* :=
{ s : B → Prop // ∀ a b, a ≤ b → s a → s b }

variable {B}

namespace copresheaf

instance : has_coe_to_fun (copresheaf B) (λ _, B → Prop) :=
⟨subtype.val⟩

@[simp] lemma coe_mk (s : B → Prop) (hs : ∀ a b, a ≤ b → s a → s b) :
  @coe_fn (copresheaf B) _ _ (⟨s, hs⟩ : copresheaf B) = s := rfl

instance : partial_order (copresheaf B) :=
{ le := λ a b, ∀ x, b x → a x,
  le_trans := λ a b c hab hbc x hcx, hab _ (hbc _ hcx),
  le_refl := λ _ _, id,
  le_antisymm := λ a b hab hba, subtype.val_injective (funext $ λ x, propext ⟨hba _, hab _⟩) }

lemma le_def {a b : copresheaf B} : a ≤ b = ∀ x, b x → a x := rfl

instance : has_Sup (copresheaf B) :=
{ Sup := λ s, ⟨λ p, ∀ B : copresheaf B, B ∈ s → B p,
     λ a b hab h B hBs, B.2 _ _ hab (h _ hBs)⟩ }

instance : complete_lattice (copresheaf B) :=
complete_lattice_of_Sup _
  (λ s, begin
    split,
    { dsimp [Sup, upper_bounds],
      intros B hBs p h,
      apply h,
      exact hBs },
    { dsimp [Inf, upper_bounds, lower_bounds],
      intros B h p hBp B hBs,
      apply h,
      exact hBs,
      exact hBp }
  end)

lemma infi_def {ι : Sort*} (a : ι → copresheaf B) :
  infi a = ⟨λ p, ∃ i, a i p, λ x y hxy ⟨i, hi⟩, ⟨i, (a i).2 x y hxy hi⟩⟩ :=
le_antisymm
  (infi_le_iff.2 (λ B h p ⟨i, hi⟩, h i _ hi))
  (le_infi_iff.2 (λ i p h, ⟨i, h⟩))

lemma supr_def {ι : Sort*} (a : ι → copresheaf B) :
  supr a = ⟨λ p, ∀ i, a i p, λ x y hxy h i, (a i).2 _ y hxy (h i)⟩ :=
le_antisymm
  (supr_le_iff.2 (λ i p h, h _))
  (le_supr_iff.2 (λ B h p hBp i, h i _ hBp))

def coyoneda (a : B) : copresheaf B :=
⟨λ b, a ≤ b, λ b c, function.swap le_trans⟩

def le_coyoneda_iff (a : copresheaf B) (p : B) : a ≤ coyoneda p ↔ a p :=
begin
  simp [copresheaf.coyoneda, copresheaf.le_def],
  split,
  { intro h, apply h, exact le_rfl },
  { intros h x hxp,
    apply a.2,
    apply hxp,
    exact h }
end

lemma coyoneda_mono {a b : B} : coyoneda a ≤ coyoneda b ↔ a ≤ b :=
begin
  rw le_coyoneda_iff, refl
end

lemma eq_infi (a : copresheaf B) : a = ⨅ (p : B) (h : a p), coyoneda p :=
begin
  apply le_antisymm; simp only [le_infi_iff, infi_le_iff, le_coyoneda_iff],
  { exact λ _, id },
  { intros B hB p,
    exact hB p }
end

def extend {B : Type*} [complete_lattice B] (f : A → B) : copresheaf A → B :=
λ a, ⨅ (p : A) (h : a p), f p

def blah1 (M : copresheaf (A × order_dual B)) : A →o presheaf B :=
{ to_fun := λ a, ⟨λ b, M (a, order_dual.to_dual b),
    λ x y hxy hM, M.2 (a, order_dual.to_dual y) _ ⟨le_rfl, hxy⟩ hM⟩,
  monotone' := λ x y hxy a ha, begin
    dsimp at *,
    refine M.2 (x, order_dual.to_dual a) _ _ _,
    split, exact hxy, refl, assumption
  end, }

def blah2 (M : copresheaf (A × order_dual B)) : B →o copresheaf A :=
{ to_fun := λ b, ⟨λ a, M (a, order_dual.to_dual b),
    λ x y hxy hM, M.2 (x, order_dual.to_dual b) _ ⟨hxy, le_rfl⟩ hM⟩,
  monotone' := λ x y hxy a ha, begin
    dsimp at *,
    refine M.2 (a, order_dual.to_dual y) _ _ _,
    split, refl, assumption, assumption
  end, }

example
  {A' B' : Type} [complete_lattice A'] [complete_lattice B']
  (M : copresheaf (A × order_dual B))
  (f : A' → B') (g : B' → A')
  (gc : galois_connection g f)
  (i : A → A') (j : B → B') (hi : monotone i) (hj : monotone j)
  (hf : ∀ x, f (i x) = presheaf.extend j (blah1 M x)) :
  ∀ x, g (j x) = copresheaf.extend i (blah2 M x) :=
begin
  intros x,
  dsimp [presheaf.extend, copresheaf.extend, blah1, blah2] at *,
  apply le_antisymm,
  { simp only [le_infi_iff],
    intros a ha,
    rw [gc.le_iff_le],
    rw hf,
    simp only [le_supr_iff, supr_le_iff],
    intros b hb,
    apply hb,
    exact ha },
  { simp only [infi_le_iff, le_infi_iff],
    intros a ha,
     }

end

example
  {A' B' : Type} [complete_lattice A'] [complete_lattice B']
  (M : copresheaf (A × order_dual B))
  (f : A' → B') (g : B' → A')
  (gc : galois_connection f g)
  (i : A → A') (j : B → B') (hi : monotone i) (hj : monotone j)
  (hf : ∀ x, f (i x) = presheaf.extend j (blah1 M x)) :
  ∀ x, g (j x) = copresheaf.extend i (blah2 M x) :=
begin
  intros x,
  dsimp [presheaf.extend, copresheaf.extend, blah1, blah2] at *,
  apply le_antisymm,
  { admit },
  { simp only [infi_le_iff, le_infi_iff],
    intros a ha,
    rw [← gc.le_iff_le],
     }

end

example {A' B' : Type} [complete_lattice A'] [complete_lattice B']
  (f : A → B) (hf : monotone f)
  (f' : A' → B') (g' : B' → A') (gc : galois_connection f' g')
  (h1 : ) :

end copresheaf

open presheaf copresheaf

variables (f : A ↪o B) (hf : ∀ b, { s : set A // is_glb (f '' s) b})

namespace presheaf

def u (a : presheaf B) : copresheaf B :=
⟨λ p, coyoneda a (yoneda p), λ a b hab h x hxA, le_trans (h _ hxA) hab⟩

lemma u_mono : monotone (@u B _):=
λ A B h p hp q hAq, hp _ (h _ hAq)

include hf

def d (a : copresheaf B) : presheaf B :=
⟨λ q, ∀ (x : A), a (f x) → q ≤ f x, λ a b hab h x hxA, le_trans hab (h _ hxA)⟩

lemma d_mono : monotone (d f hf) :=
λ A B h p hp q hAq, hp _ (h _ hAq)

def gc : galois_connection u (d f hf) :=
begin
  intros a b,
  dsimp [presheaf.u, presheaf.d],
  split,
  { intros h x hxA y hyB,
    dsimp [copresheaf.le_def] at h,
    apply h,
    assumption,
    assumption },
  { intros h x hxA y hyB,
    dsimp [presheaf.le_def] at *,
    dsimp [yoneda],
    cases hf x with s hs,
    rw [le_is_glb_iff hs, mem_lower_bounds],
    intros z hz,
    rcases hz with ⟨z, hz, rfl⟩,
    apply h,
    assumption,
    rw [← le_coyoneda_iff] at *,
    refine le_trans hxA _,
    refine coyoneda_mono.2 _,
    exact hs.1 (set.mem_image_of_mem _ hz) }
end

omit hf

open copresheaf

@[simp] lemma le_d_u (a : presheaf B) : a ≤ d f hf (u a) := (gc f hf).le_u_l a

@[simp] lemma u_d_u (a : presheaf B) : u (d f hf (u a)) = u a :=
(gc f hf).l_u_l_eq_l a

@[simp] lemma u_yoneda (p : B) : u (yoneda p) = coyoneda p :=
begin
  rw [u],
  conv_lhs { dsimp [coyoneda] },
  simp only [yoneda_le_iff],
  refl
end

end presheaf

namespace copresheaf

open presheaf

lemma u_d_le (a : copresheaf B) : u (d f hf a) ≤ a := (gc f hf).l_u_le a

@[simp] lemma d_u_d (a : copresheaf B) : d f hf (u (d f hf a)) = d f hf a :=
(gc f hf).u_l_u_eq_u _

include hf

@[simp] lemma d_coyoneda (p : B) : d f hf (coyoneda p) = yoneda p :=
begin
  rw [d],
  ext,
  dsimp,
  split,
  { intros h,
    dsimp [yoneda],
    cases hf p with s hs,
    rw [le_is_glb_iff hs, mem_lower_bounds],
    simp only [set.mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂],
    intros a ha,
    apply h,
    apply hs.1,
    exact set.mem_image_of_mem _ ha  },
  { intros h y py,
    exact le_trans h py }
end

end copresheaf

open presheaf copresheaf

variable {B}

include hf

/- Aiming to construct a pscompletion of `B` that preserves all sups in `A`.
  So if we have a partial order `C` a monotone function `B -> C` and a `sup_hom`
  from `A -> C` that commute with `f` there is a unique cocontinuous map from
  the pscompletion to `C` such that everything commutes. -/

structure pscompletion : Type v :=
( to_presheaf : presheaf B )
( fixed : d f hf (u to_presheaf) = to_presheaf )

namespace pscompletion

variables {B}

def _root_.presheaf.to_pscompletion (a : presheaf B) : pscompletion f hf :=
⟨d f hf (u a), by simp *⟩

instance : partial_order (pscompletion f hf) :=
partial_order.lift pscompletion.to_presheaf
  begin
    rintros ⟨_, _⟩ ⟨_, _⟩,
    simp
  end

lemma le_def {a b : pscompletion f hf} : a ≤ b ↔ a.to_presheaf ≤ b.to_presheaf := iff.rfl

def gi : galois_insertion (_root_.presheaf.to_pscompletion f hf) pscompletion.to_presheaf :=
galois_connection.to_galois_insertion
  begin
    intros x y,
    simp only [_root_.presheaf.to_pscompletion, le_def],
    rw [← y.fixed, ← (gc f hf).le_iff_le, u_d_u f hf, (gc f hf).le_iff_le],
  end
  (by simp [_root_.presheaf.to_pscompletion, le_def, le_d_u f hf])

instance : complete_lattice (pscompletion f hf) :=
galois_insertion.lift_complete_lattice (gi f hf)

lemma supr_to_presheaf {ι : Sort*} (a : ι → pscompletion f hf) :
  (supr a).to_presheaf = d f hf (⨆ i, (a i).to_presheaf).u :=
begin
  rw ← (gi f hf).l_supr_u, refl,
end

@[simps] def of_partial_order (a : B) : pscompletion f hf :=
⟨yoneda a, by rw [u_yoneda, d_coyoneda f hf]⟩

@[simp] lemma of_partial_order_mono {a b : B} : of_partial_order f hf a ≤ of_partial_order f hf b ↔ a ≤ b :=
yoneda_mono

lemma of_partial_order_le_iff (a : B) (x : pscompletion f hf) :
  of_partial_order f hf a ≤ x ↔ x.to_presheaf a :=
by simp only [of_partial_order, le_def, yoneda_le_iff]

lemma of_partial_order_lub (s : set A) (a : A) (h : is_lub s a) :
  is_lub (of_partial_order f hf '' (f '' s)) (of_partial_order f hf (f a)) :=
begin
  split,
  { simp only [upper_bounds, set.mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, set.mem_set_of_eq,
      of_partial_order_mono],
    intros b hbs,
    exact f.monotone (h.1 hbs) },
  { simp only [upper_bounds, lower_bounds, set.mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂,
      set.mem_set_of_eq],
    intros x hx,
    cases x with x x_fixed,
    refine (yoneda_le_iff _ _).2 _,
    dsimp,
    simp only [le_def, of_partial_order_to_presheaf, yoneda_le_iff] at hx,
    rw [← x_fixed],
    dsimp [d, u],
    intros b hb,
    simp [coyoneda, presheaf.le_def, yoneda] at hb,
    refine f.monotone _,
    apply h.2,
    intros c hc,
    apply f.le_iff_le.1,
    apply hb,
    apply hx,
    exact hc }
end

variables {C : Type*} [complete_lattice C] (i : B →o C)

def ump : pscompletion f hf → C :=
λ x, ⨆ (b : B) (h : x.to_presheaf b), i b

lemma ump_supr {ι : Sort*} (a : ι → pscompletion f hf) : ump f hf i (supr a) = ⨆ j, ump f hf i (a j) :=
begin
  dsimp [ump],
  simp only [supr_to_presheaf],
  simp only [of_partial_order_le_iff, le_antisymm_iff, supr_le_iff, le_supr_iff],
  split,
  { intros c h₁ b h₂,
    simp [d, u, coyoneda, yoneda, le_def, presheaf.le_def, presheaf.supr_def] at h₂,
    apply h₁,
    apply h₂,
    intros i, admit,  admit},
  { intros c h₁ j b h₂,
    apply h₁,
    intros x h,
    refine h j _ _,
    exact h₂ }
end

end pscompletion


import LeanExt

namespace Day8

structure Tree where
  size : Nat
  pos : Nat × Nat
deriving Repr, Inhabited

def Tree.visibleOutside : List Tree → List Tree
  | [] => []
  | t :: ts =>
    t :: loop t ts
  where
  loop (tMax:Tree) : List Tree → List Tree
    | [] => []
    | t :: ts =>
      if t.size > tMax.size
      then t :: loop t ts
      else loop tMax ts

theorem Tree.visibleOutside.loop_idempotent {t:Tree} {ts:List Tree}
  : visibleOutside.loop t ts = visibleOutside.loop t (visibleOutside.loop t ts)
  := by
  cases ts <;> simp [loop]
  split <;> simp [loop, *] <;> apply loop_idempotent

theorem Tree.visibleOutside_idempotent {ts:List Tree}
  : Tree.visibleOutside ts = Tree.visibleOutside (Tree.visibleOutside ts)
  := by
  cases ts <;> simp [visibleOutside]
  apply Tree.visibleOutside.loop_idempotent
  -- 🎉 finally, just took a rewrite of Tree.visibleOutside

def Tree.treeHouseVisible (acc:List (Tree × List Tree)) : List Tree → List (Tree × List Tree)
  | [] => acc.reverse
  | t₁ :: ts₁ =>
    let rec visible (acc:List Tree) : List Tree → List Tree
      | [] => acc.reverse
      | t₂ :: ts₂ =>
        let acc := t₂ :: acc
        if t₂.size < t₁.size then
          visible acc ts₂
        else
          acc |>.reverse
    Tree.treeHouseVisible ((t₁, visible [] ts₁) :: acc) ts₁

def Tree.allSides (tss:List (List Tree)) : List (List Tree) :=
  let left := tss
  let right := left |>.map List.reverse
  let top := tss.transpose!
  let bottom := top |>.map List.reverse
  [left, right, top, bottom].join

namespace Parse
  def tree! (ls:List String) : List (List Tree) :=
    ls
    |>.enum
    |>.map (fun (x, l) =>
      l.toList
      |>.map (fun c => c.toNat - '0'.toNat)
      |>.enum
      |>.map (fun (y, size) => {size := size, pos := (x, y) :Tree})
    )
end Parse

def part1 (ls:List String) :=
  ls
  |> Parse.tree!
  |> Tree.allSides
  |>.map Tree.visibleOutside
  |>.join
  |>.map Tree.pos
  |>.eraseDups
  |>.length

def part2 (ls:List String) :=
  ls
  |> Parse.tree!
  |> Tree.allSides
  |>.bind (Tree.treeHouseVisible [])
  |>.groupByEx (fun (t, ts) => (t.pos, ts.length))
  |>.map (List.foldl (·*·) 1 ∘ Prod.snd)
  |>.maximum?
  |>.get!

def testInput :=
  [ "30373"
  , "25512"
  , "65332"
  , "33549"
  , "35390"
  ]
#eval 21 <== part1 testInput
#eval 8 <== part2 testInput

end Day8