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

! This file was ported from Lean 3 source module data.finsupp.lex
! leanprover-community/mathlib commit 1ead22342e1a078bd44744ace999f85756555d35
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Finsupp.Order
import Mathbin.Data.Dfinsupp.Lex
import Mathbin.Data.Finsupp.ToDfinsupp

/-!
# Lexicographic order on finitely supported functions

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

This file defines the lexicographic order on `finsupp`.
-/

variable {α N : Type _}

namespace Finsupp

section NHasZero

variable [Zero N]

#print Finsupp.Lex /-
/-- `finsupp.lex r s` is the lexicographic relation on `α →₀ N`, where `α` is ordered by `r`,
and `N` is ordered by `s`.

The type synonym `lex (α →₀ N)` has an order given by `finsupp.lex (<) (<)`.
-/
protected def Lex (r : α → α → Prop) (s : N → N → Prop) (x y : α →₀ N) : Prop :=
  Pi.Lex r (fun _ => s) x y
#align finsupp.lex Finsupp.Lex
-/

/- warning: pi.lex_eq_finsupp_lex -> Pi.lex_eq_finsupp_lex is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : Zero.{u2} N] {r : α -> α -> Prop} {s : N -> N -> Prop} (a : Finsupp.{u1, u2} α N _inst_1) (b : Finsupp.{u1, u2} α N _inst_1), Eq.{1} Prop (Pi.Lex.{u1, u2} α (fun (_x : α) => N) r (fun (_x : α) => s) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} α N _inst_1) (fun (_x : Finsupp.{u1, u2} α N _inst_1) => α -> N) (Finsupp.coeFun.{u1, u2} α N _inst_1) a) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} α N _inst_1) (fun (_x : Finsupp.{u1, u2} α N _inst_1) => α -> N) (Finsupp.coeFun.{u1, u2} α N _inst_1) b)) (Finsupp.Lex.{u1, u2} α N _inst_1 r s a b)
but is expected to have type
  forall {α : Type.{u2}} {N : Type.{u1}} [_inst_1 : Zero.{u1} N] {r : α -> α -> Prop} {s : N -> N -> Prop} (a : Finsupp.{u2, u1} α N _inst_1) (b : Finsupp.{u2, u1} α N _inst_1), Eq.{1} Prop (Pi.Lex.{u2, u1} α (fun {_x : α} => N) r (fun {_x : α} => s) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} α N _inst_1) α (fun (_x : α) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) _x) (Finsupp.funLike.{u2, u1} α N _inst_1) a) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} α N _inst_1) α (fun (_x : α) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) _x) (Finsupp.funLike.{u2, u1} α N _inst_1) b)) (Finsupp.Lex.{u2, u1} α N _inst_1 r s a b)
Case conversion may be inaccurate. Consider using '#align pi.lex_eq_finsupp_lex Pi.lex_eq_finsupp_lexₓ'. -/
theorem Pi.lex_eq_finsupp_lex {r : α → α → Prop} {s : N → N → Prop} (a b : α →₀ N) :
    Pi.Lex r (fun _ => s) (a : α → N) (b : α → N) = Finsupp.Lex r s a b :=
  rfl
#align pi.lex_eq_finsupp_lex Pi.lex_eq_finsupp_lex

/- warning: finsupp.lex_def -> Finsupp.lex_def is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : Zero.{u2} N] {r : α -> α -> Prop} {s : N -> N -> Prop} {a : Finsupp.{u1, u2} α N _inst_1} {b : Finsupp.{u1, u2} α N _inst_1}, Iff (Finsupp.Lex.{u1, u2} α N _inst_1 r s a b) (Exists.{succ u1} α (fun (j : α) => And (forall (d : α), (r d j) -> (Eq.{succ u2} N (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} α N _inst_1) (fun (_x : Finsupp.{u1, u2} α N _inst_1) => α -> N) (Finsupp.coeFun.{u1, u2} α N _inst_1) a d) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} α N _inst_1) (fun (_x : Finsupp.{u1, u2} α N _inst_1) => α -> N) (Finsupp.coeFun.{u1, u2} α N _inst_1) b d))) (s (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} α N _inst_1) (fun (_x : Finsupp.{u1, u2} α N _inst_1) => α -> N) (Finsupp.coeFun.{u1, u2} α N _inst_1) a j) (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u1, u2} α N _inst_1) (fun (_x : Finsupp.{u1, u2} α N _inst_1) => α -> N) (Finsupp.coeFun.{u1, u2} α N _inst_1) b j))))
but is expected to have type
  forall {α : Type.{u2}} {N : Type.{u1}} [_inst_1 : Zero.{u1} N] {r : α -> α -> Prop} {s : N -> N -> Prop} {a : Finsupp.{u2, u1} α N _inst_1} {b : Finsupp.{u2, u1} α N _inst_1}, Iff (Finsupp.Lex.{u2, u1} α N _inst_1 r s a b) (Exists.{succ u2} α (fun (j : α) => And (forall (d : α), (r d j) -> (Eq.{succ u1} ((fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) d) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} α N _inst_1) α (fun (_x : α) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) _x) (Finsupp.funLike.{u2, u1} α N _inst_1) a d) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} α N _inst_1) α (fun (_x : α) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) _x) (Finsupp.funLike.{u2, u1} α N _inst_1) b d))) (s (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} α N _inst_1) α (fun (_x : α) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) _x) (Finsupp.funLike.{u2, u1} α N _inst_1) a j) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Finsupp.{u2, u1} α N _inst_1) α (fun (_x : α) => (fun (x._@.Mathlib.Data.Finsupp.Defs._hyg.779 : α) => N) _x) (Finsupp.funLike.{u2, u1} α N _inst_1) b j))))
Case conversion may be inaccurate. Consider using '#align finsupp.lex_def Finsupp.lex_defₓ'. -/
theorem lex_def {r : α → α → Prop} {s : N → N → Prop} {a b : α →₀ N} :
    Finsupp.Lex r s a b ↔ ∃ j, (∀ d, r d j → a d = b d) ∧ s (a j) (b j) :=
  Iff.rfl
#align finsupp.lex_def Finsupp.lex_def

/- warning: finsupp.lex_eq_inv_image_dfinsupp_lex -> Finsupp.lex_eq_invImage_dfinsupp_lex is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : Zero.{u2} N] (r : α -> α -> Prop) (s : N -> N -> Prop), Eq.{max (max (succ u1) (succ u2)) 1} ((Finsupp.{u1, u2} α N _inst_1) -> (Finsupp.{u1, u2} α N _inst_1) -> Prop) (Finsupp.Lex.{u1, u2} α N _inst_1 r s) (InvImage.{max (succ u1) (succ u2), succ (max u1 u2)} (Finsupp.{u1, u2} α N _inst_1) (Dfinsupp.{u1, u2} α (fun (i : α) => N) (fun (i : α) => _inst_1)) (Dfinsupp.Lex.{u1, u2} α (fun (a : α) => N) (fun (i : α) => _inst_1) r (fun (a : α) => s)) (Finsupp.toDfinsupp.{u1, u2} α N _inst_1))
but is expected to have type
  forall {α : Type.{u2}} {N : Type.{u1}} [_inst_1 : Zero.{u1} N] (r : α -> α -> Prop) (s : N -> N -> Prop), Eq.{max (succ u2) (succ u1)} ((Finsupp.{u2, u1} α N _inst_1) -> (Finsupp.{u2, u1} α N _inst_1) -> Prop) (Finsupp.Lex.{u2, u1} α N _inst_1 r s) (InvImage.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (Finsupp.{u2, u1} α N _inst_1) (Dfinsupp.{u2, u1} α (fun (i : α) => N) (fun (i : α) => _inst_1)) (Dfinsupp.Lex.{u2, u1} α (fun (a : α) => N) (fun (i : α) => _inst_1) r (fun (a : α) => s)) (Finsupp.toDfinsupp.{u2, u1} α N _inst_1))
Case conversion may be inaccurate. Consider using '#align finsupp.lex_eq_inv_image_dfinsupp_lex Finsupp.lex_eq_invImage_dfinsupp_lexₓ'. -/
theorem lex_eq_invImage_dfinsupp_lex (r : α → α → Prop) (s : N → N → Prop) :
    Finsupp.Lex r s = InvImage (Dfinsupp.Lex r fun a => s) toDfinsupp :=
  rfl
#align finsupp.lex_eq_inv_image_dfinsupp_lex Finsupp.lex_eq_invImage_dfinsupp_lex

instance [LT α] [LT N] : LT (Lex (α →₀ N)) :=
  ⟨fun f g => Finsupp.Lex (· < ·) (· < ·) (ofLex f) (ofLex g)⟩

#print Finsupp.lex_lt_of_lt_of_preorder /-
theorem lex_lt_of_lt_of_preorder [Preorder N] (r) [IsStrictOrder α r] {x y : α →₀ N} (hlt : x < y) :
    ∃ i, (∀ j, r j i → x j ≤ y j ∧ y j ≤ x j) ∧ x i < y i :=
  Dfinsupp.lex_lt_of_lt_of_preorder r (id hlt : x.toDfinsupp < y.toDfinsupp)
#align finsupp.lex_lt_of_lt_of_preorder Finsupp.lex_lt_of_lt_of_preorder
-/

#print Finsupp.lex_lt_of_lt /-
theorem lex_lt_of_lt [PartialOrder N] (r) [IsStrictOrder α r] {x y : α →₀ N} (hlt : x < y) :
    Pi.Lex r (fun i => (· < ·)) x y :=
  Dfinsupp.lex_lt_of_lt r (id hlt : x.toDfinsupp < y.toDfinsupp)
#align finsupp.lex_lt_of_lt Finsupp.lex_lt_of_lt
-/

/- warning: finsupp.lex.is_strict_order -> Finsupp.Lex.isStrictOrder is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : Zero.{u2} N] [_inst_2 : LinearOrder.{u1} α] [_inst_3 : PartialOrder.{u2} N], IsStrictOrder.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1)) (LT.lt.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1)) (Finsupp.Lex.hasLt.{u1, u2} α N _inst_1 (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_2))))) (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N _inst_3))))
but is expected to have type
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : Zero.{u2} N] [_inst_2 : LinearOrder.{u1} α] [_inst_3 : PartialOrder.{u2} N], IsStrictOrder.{max u2 u1} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N _inst_1)) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.457 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N _inst_1)) (x._@.Mathlib.Data.Finsupp.Lex._hyg.459 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N _inst_1)) => LT.lt.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N _inst_1)) (Finsupp.instLTLexFinsupp.{u1, u2} α N _inst_1 (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_2)))))) (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N _inst_3))) x._@.Mathlib.Data.Finsupp.Lex._hyg.457 x._@.Mathlib.Data.Finsupp.Lex._hyg.459)
Case conversion may be inaccurate. Consider using '#align finsupp.lex.is_strict_order Finsupp.Lex.isStrictOrderₓ'. -/
instance Lex.isStrictOrder [LinearOrder α] [PartialOrder N] :
    IsStrictOrder (Lex (α →₀ N)) (· < ·) :=
  let i : IsStrictOrder (Lex (α → N)) (· < ·) := Pi.Lex.isStrictOrder
  { irrefl := toLex.Surjective.forall.2 fun a => @irrefl _ _ i.to_isIrrefl a
    trans := toLex.Surjective.forall₃.2 fun a b c => @trans _ _ i.to_isTrans a b c }
#align finsupp.lex.is_strict_order Finsupp.Lex.isStrictOrder

variable [LinearOrder α]

#print Finsupp.Lex.partialOrder /-
/-- The partial order on `finsupp`s obtained by the lexicographic ordering.
See `finsupp.lex.linear_order` for a proof that this partial order is in fact linear. -/
instance Lex.partialOrder [PartialOrder N] : PartialOrder (Lex (α →₀ N)) :=
  PartialOrder.lift (fun x => toLex ⇑(ofLex x)) Finsupp.coeFn_injective
#align finsupp.lex.partial_order Finsupp.Lex.partialOrder
-/

#print Finsupp.Lex.linearOrder /-
--fun_like.coe_injective
/-- The linear order on `finsupp`s obtained by the lexicographic ordering. -/
instance Lex.linearOrder [LinearOrder N] : LinearOrder (Lex (α →₀ N)) :=
  { Lex.partialOrder,
    LinearOrder.lift' (toLex ∘ toDfinsupp ∘ ofLex) finsuppEquivDfinsupp.Injective with }
#align finsupp.lex.linear_order Finsupp.Lex.linearOrder
-/

variable [PartialOrder N]

/- warning: finsupp.to_lex_monotone -> Finsupp.toLex_monotone is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : Zero.{u2} N] [_inst_2 : LinearOrder.{u1} α] [_inst_3 : PartialOrder.{u2} N], Monotone.{max u1 u2, max u1 u2} (Finsupp.{u1, u2} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1)) (Finsupp.preorder.{u1, u2} α N _inst_1 (PartialOrder.toPreorder.{u2} N _inst_3)) (PartialOrder.toPreorder.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1)) (Finsupp.Lex.partialOrder.{u1, u2} α N _inst_1 _inst_2 _inst_3)) (coeFn.{succ (max u1 u2), succ (max u1 u2)} (Equiv.{succ (max u1 u2), succ (max u1 u2)} (Finsupp.{u1, u2} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1))) (fun (_x : Equiv.{succ (max u1 u2), succ (max u1 u2)} (Finsupp.{u1, u2} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1))) => (Finsupp.{u1, u2} α N _inst_1) -> (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1))) (Equiv.hasCoeToFun.{succ (max u1 u2), succ (max u1 u2)} (Finsupp.{u1, u2} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1))) (toLex.{max u1 u2} (Finsupp.{u1, u2} α N _inst_1)))
but is expected to have type
  forall {α : Type.{u2}} {N : Type.{u1}} [_inst_1 : Zero.{u1} N] [_inst_2 : LinearOrder.{u2} α] [_inst_3 : PartialOrder.{u1} N], Monotone.{max u2 u1, max u2 u1} (Finsupp.{u2, u1} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u2, u1} α N _inst_1)) (Finsupp.preorder.{u2, u1} α N _inst_1 (PartialOrder.toPreorder.{u1} N _inst_3)) (PartialOrder.toPreorder.{max u2 u1} (Lex.{max u1 u2} (Finsupp.{u2, u1} α N _inst_1)) (Finsupp.Lex.partialOrder.{u2, u1} α N _inst_1 _inst_2 _inst_3)) (FunLike.coe.{max (succ u2) (succ u1), max (succ u2) (succ u1), max (succ u2) (succ u1)} (Equiv.{succ (max u1 u2), succ (max u1 u2)} (Finsupp.{u2, u1} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u2, u1} α N _inst_1))) (Finsupp.{u2, u1} α N _inst_1) (fun (_x : Finsupp.{u2, u1} α N _inst_1) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : Finsupp.{u2, u1} α N _inst_1) => Lex.{max u1 u2} (Finsupp.{u2, u1} α N _inst_1)) _x) (Equiv.instFunLikeEquiv.{max (succ u2) (succ u1), max (succ u2) (succ u1)} (Finsupp.{u2, u1} α N _inst_1) (Lex.{max u1 u2} (Finsupp.{u2, u1} α N _inst_1))) (toLex.{max u1 u2} (Finsupp.{u2, u1} α N _inst_1)))
Case conversion may be inaccurate. Consider using '#align finsupp.to_lex_monotone Finsupp.toLex_monotoneₓ'. -/
theorem toLex_monotone : Monotone (@toLex (α →₀ N)) := fun a b h =>
  Dfinsupp.toLex_monotone (id h : ∀ i, ofLex (toDfinsupp a) i ≤ ofLex (toDfinsupp b) i)
#align finsupp.to_lex_monotone Finsupp.toLex_monotone

#print Finsupp.lt_of_forall_lt_of_lt /-
theorem lt_of_forall_lt_of_lt (a b : Lex (α →₀ N)) (i : α) :
    (∀ j < i, ofLex a j = ofLex b j) → ofLex a i < ofLex b i → a < b := fun h1 h2 => ⟨i, h1, h2⟩
#align finsupp.lt_of_forall_lt_of_lt Finsupp.lt_of_forall_lt_of_lt
-/

end NHasZero

section Covariants

variable [LinearOrder α] [AddMonoid N] [LinearOrder N]

/-!  We are about to sneak in a hypothesis that might appear to be too strong.
We assume `covariant_class` with *strict* inequality `<` also when proving the one with the
*weak* inequality `≤`.  This is actually necessary: addition on `lex (α →₀ N)` may fail to be
monotone, when it is "just" monotone on `N`.

See `counterexamples.zero_divisors_in_add_monoid_algebras` for a counterexample. -/

section Left

variable [CovariantClass N N (· + ·) (· < ·)]

/- warning: finsupp.lex.covariant_class_lt_left -> Finsupp.Lex.covariantClass_lt_left is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toHasAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3))))))], CovariantClass.{max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (instHAdd.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.hasAdd.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2))))) (LT.lt.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Finsupp.Lex.hasLt.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)) (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1))))) (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3)))))))
but is expected to have type
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.968 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.970 : N) => HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) x._@.Mathlib.Data.Finsupp.Lex._hyg.968 x._@.Mathlib.Data.Finsupp.Lex._hyg.970) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.983 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.985 : N) => LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3)))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.983 x._@.Mathlib.Data.Finsupp.Lex._hyg.985)], CovariantClass.{max u2 u1, max u2 u1} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1019 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1021 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instHAdd.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instAddLex.{max u1 u2} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2)) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1019 x._@.Mathlib.Data.Finsupp.Lex._hyg.1021) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1034 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1036 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => LT.lt.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Finsupp.instLTLexFinsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2) (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1)))))) (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3))))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1034 x._@.Mathlib.Data.Finsupp.Lex._hyg.1036)
Case conversion may be inaccurate. Consider using '#align finsupp.lex.covariant_class_lt_left Finsupp.Lex.covariantClass_lt_leftₓ'. -/
instance Lex.covariantClass_lt_left :
    CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (· + ·) (· < ·) :=
  ⟨fun f g h ⟨a, lta, ha⟩ =>
    ⟨a, fun j ja => congr_arg ((· + ·) _) (lta j ja), add_lt_add_left ha _⟩⟩
#align finsupp.lex.covariant_class_lt_left Finsupp.Lex.covariantClass_lt_left

/- warning: finsupp.lex.covariant_class_le_left -> Finsupp.Lex.covariantClass_le_left is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toHasAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3))))))], CovariantClass.{max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (instHAdd.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.hasAdd.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2))))) (LE.le.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Preorder.toLE.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (PartialOrder.toPreorder.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Finsupp.Lex.partialOrder.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)) _inst_1 (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3)))))))
but is expected to have type
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1123 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1125 : N) => HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1123 x._@.Mathlib.Data.Finsupp.Lex._hyg.1125) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1138 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1140 : N) => LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3)))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1138 x._@.Mathlib.Data.Finsupp.Lex._hyg.1140)], CovariantClass.{max u2 u1, max u2 u1} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1174 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1176 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instHAdd.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instAddLex.{max u1 u2} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2)) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1174 x._@.Mathlib.Data.Finsupp.Lex._hyg.1176) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1189 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1191 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => LE.le.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Preorder.toLE.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (PartialOrder.toPreorder.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Finsupp.Lex.partialOrder.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2) _inst_1 (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3))))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1189 x._@.Mathlib.Data.Finsupp.Lex._hyg.1191)
Case conversion may be inaccurate. Consider using '#align finsupp.lex.covariant_class_le_left Finsupp.Lex.covariantClass_le_leftₓ'. -/
instance Lex.covariantClass_le_left :
    CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (· + ·) (· ≤ ·) :=
  Add.to_covariantClass_left _
#align finsupp.lex.covariant_class_le_left Finsupp.Lex.covariantClass_le_left

end Left

section Right

variable [CovariantClass N N (Function.swap (· + ·)) (· < ·)]

/- warning: finsupp.lex.covariant_class_lt_right -> Finsupp.Lex.covariantClass_lt_right is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (Function.swap.{succ u2, succ u2, succ u2} N N (fun (ᾰ : N) (ᾰ : N) => N) (HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toHasAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))))) (LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3))))))], CovariantClass.{max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Function.swap.{succ (max u1 u2), succ (max u1 u2), succ (max u1 u2)} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (fun (ᾰ : Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (ᾰ : Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) => Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (instHAdd.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.hasAdd.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))))) (LT.lt.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Finsupp.Lex.hasLt.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)) (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1))))) (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3)))))))
but is expected to have type
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (Function.swap.{succ u2, succ u2, succ u2} N N (fun (ᾰ : N) (ᾰ : N) => N) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1282 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1284 : N) => HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1282 x._@.Mathlib.Data.Finsupp.Lex._hyg.1284)) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1297 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1299 : N) => LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3)))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1297 x._@.Mathlib.Data.Finsupp.Lex._hyg.1299)], CovariantClass.{max u2 u1, max u2 u1} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Function.swap.{max (succ u1) (succ u2), max (succ u1) (succ u2), max (succ u1) (succ u2)} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (fun (ᾰ : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (ᾰ : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1336 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1338 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instHAdd.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instAddLex.{max u1 u2} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2)) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1336 x._@.Mathlib.Data.Finsupp.Lex._hyg.1338)) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1351 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1353 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => LT.lt.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Finsupp.instLTLexFinsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2) (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1)))))) (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3))))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1351 x._@.Mathlib.Data.Finsupp.Lex._hyg.1353)
Case conversion may be inaccurate. Consider using '#align finsupp.lex.covariant_class_lt_right Finsupp.Lex.covariantClass_lt_rightₓ'. -/
instance Lex.covariantClass_lt_right :
    CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (Function.swap (· + ·)) (· < ·) :=
  ⟨fun f g h ⟨a, lta, ha⟩ =>
    ⟨a, fun j ja => congr_arg (· + ofLex f j) (lta j ja), add_lt_add_right ha _⟩⟩
#align finsupp.lex.covariant_class_lt_right Finsupp.Lex.covariantClass_lt_right

/- warning: finsupp.lex.covariant_class_le_right -> Finsupp.Lex.covariantClass_le_right is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (Function.swap.{succ u2, succ u2, succ u2} N N (fun (ᾰ : N) (ᾰ : N) => N) (HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toHasAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))))) (LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3))))))], CovariantClass.{max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Function.swap.{succ (max u1 u2), succ (max u1 u2), succ (max u1 u2)} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (fun (ᾰ : Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (ᾰ : Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) => Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (instHAdd.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Lex.hasAdd.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))))) (LE.le.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Preorder.toLE.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (PartialOrder.toPreorder.{max u1 u2} (Lex.{max u1 u2} (Finsupp.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) (Finsupp.Lex.partialOrder.{u1, u2} α N (AddZeroClass.toHasZero.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2)) _inst_1 (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (LinearOrder.toLattice.{u2} N _inst_3)))))))
but is expected to have type
  forall {α : Type.{u1}} {N : Type.{u2}} [_inst_1 : LinearOrder.{u1} α] [_inst_2 : AddMonoid.{u2} N] [_inst_3 : LinearOrder.{u2} N] [_inst_4 : CovariantClass.{u2, u2} N N (Function.swap.{succ u2, succ u2, succ u2} N N (fun (ᾰ : N) (ᾰ : N) => N) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1457 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1459 : N) => HAdd.hAdd.{u2, u2, u2} N N N (instHAdd.{u2} N (AddZeroClass.toAdd.{u2} N (AddMonoid.toAddZeroClass.{u2} N _inst_2))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1457 x._@.Mathlib.Data.Finsupp.Lex._hyg.1459)) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1472 : N) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1474 : N) => LT.lt.{u2} N (Preorder.toLT.{u2} N (PartialOrder.toPreorder.{u2} N (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3)))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1472 x._@.Mathlib.Data.Finsupp.Lex._hyg.1474)], CovariantClass.{max u2 u1, max u2 u1} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Function.swap.{max (succ u1) (succ u2), max (succ u1) (succ u2), max (succ u1) (succ u2)} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (fun (ᾰ : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (ᾰ : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1511 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1513 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => HAdd.hAdd.{max u1 u2, max u1 u2, max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instHAdd.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (instAddLex.{max u1 u2} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2)) (Finsupp.add.{u1, u2} α N (AddMonoid.toAddZeroClass.{u2} N _inst_2)))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1511 x._@.Mathlib.Data.Finsupp.Lex._hyg.1513)) (fun (x._@.Mathlib.Data.Finsupp.Lex._hyg.1526 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (x._@.Mathlib.Data.Finsupp.Lex._hyg.1528 : Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) => LE.le.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Preorder.toLE.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (PartialOrder.toPreorder.{max u1 u2} (Lex.{max u2 u1} (Finsupp.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2))) (Finsupp.Lex.partialOrder.{u1, u2} α N (AddMonoid.toZero.{u2} N _inst_2) _inst_1 (SemilatticeInf.toPartialOrder.{u2} N (Lattice.toSemilatticeInf.{u2} N (DistribLattice.toLattice.{u2} N (instDistribLattice.{u2} N _inst_3))))))) x._@.Mathlib.Data.Finsupp.Lex._hyg.1526 x._@.Mathlib.Data.Finsupp.Lex._hyg.1528)
Case conversion may be inaccurate. Consider using '#align finsupp.lex.covariant_class_le_right Finsupp.Lex.covariantClass_le_rightₓ'. -/
instance Lex.covariantClass_le_right :
    CovariantClass (Lex (α →₀ N)) (Lex (α →₀ N)) (Function.swap (· + ·)) (· ≤ ·) :=
  Add.to_covariantClass_right _
#align finsupp.lex.covariant_class_le_right Finsupp.Lex.covariantClass_le_right

end Right

end Covariants

end Finsupp


/-
Copyright (c) 2020 Simon Hudon. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Simon Hudon
-/
import topology.basic
import order.omega_complete_partial_order

/-!
# Scott Topological Spaces

A type of topological spaces whose notion
of continuity is equivalent to continuity in ωCPOs.

## Reference

 * https://ncatlab.org/nlab/show/Scott+topology

-/

open omega_complete_partial_order
open_locale classical

universes u
namespace Scott

/--  -/
def is_ωSup {α : Type u} [preorder α] (c : chain α) (x : α) : Prop :=
(∀ i, c i ≤ x) ∧ (∀ y, (∀ i, c i ≤ y) → x ≤ y)

variables (α : Type u) [omega_complete_partial_order α]
local attribute [irreducible] set

/-- The characteristic function of open sets is monotone and preserves
the limits of chains. -/
def is_open (s : set α) : Prop :=
continuous' (λ x, x ∈ s)

theorem is_open_univ : is_open α set.univ :=
⟨λ x y h, by simp only [set.mem_univ]; refl',
  by convert @complete_lattice.top_continuous α Prop _ _; ext; simp ⟩

theorem is_open_inter (s t : set α) : is_open α s → is_open α t → is_open α (s ∩ t) :=
begin
  simp only [is_open, exists_imp_distrib, continuous'],
  intros h₀ h₁ h₂ h₃,
  rw ← set.inf_eq_inter,
  let s' : α →ₘ Prop := ⟨λ x, x ∈ s, h₀⟩,
  let t' : α →ₘ Prop := ⟨λ x, x ∈ t, h₂⟩,
  split,
  { change omega_complete_partial_order.continuous (s' ⊓ t'),
    haveI : is_total Prop (≤) := ⟨ @le_total Prop _ ⟩,
    apply complete_lattice.inf_continuous; assumption },
  { intros x y h, apply and_implies;
    solve_by_elim [h₀ h, h₂ h], }
end

theorem is_open_sUnion : ∀s, (∀t∈s, is_open α t) → is_open α (⋃₀ s) :=
begin
  introv h₀,
  suffices : is_open α ({ x | Sup (flip (∈) '' s) x }),
  { convert this, ext,
    simp only [set.sUnion, Sup, set.mem_image, set.mem_set_of_eq, supr,
               conditionally_complete_lattice.Sup, exists_exists_and_eq_and,
               complete_lattice.Sup, exists_prop, set.mem_range,
               set_coe.exists, eq_iff_iff, subtype.coe_mk],
    tauto, },
  dsimp [is_open] at *,
  apply complete_lattice.Sup_continuous' _,
  introv ht, specialize h₀ { x | t x } _,
  { simp only [flip, set.mem_image] at *,
    rcases ht with ⟨x,h₀,h₁⟩, subst h₁,
    simpa, },
  { simpa using h₀ }
end

end Scott

/-- A Scott topological space is defined on preorders
such that their open sets, seen as a function `α → Prop`,
preserves the joins of ω-chains  -/
@[reducible]
def Scott (α : Type u) := α

instance Scott.topological_space (α : Type u) [omega_complete_partial_order α] :
  topological_space (Scott α) :=
{ is_open := Scott.is_open α,
  is_open_univ := Scott.is_open_univ α,
  is_open_inter := Scott.is_open_inter α,
  is_open_sUnion := Scott.is_open_sUnion α }

section not_below
variables {α : Type*} [omega_complete_partial_order α] (y : Scott α)

/-- `not_below` is an open set in `Scott α` used
to prove the monotonicity of continuous functions -/
def not_below := { x | ¬ x ≤ y }

lemma not_below_is_open : is_open (not_below y) :=
begin
  have h : monotone (not_below y),
  { intros x y' h,
    simp only [not_below, set_of, le_iff_imp],
    intros h₀ h₁, apply h₀ (le_trans h h₁) },
  existsi h, rintros c,
  apply eq_of_forall_ge_iff, intro z,
  rw ωSup_le_iff,
  simp only [ωSup_le_iff, not_below, set.mem_set_of_eq, le_iff_imp, preorder_hom.coe_fun_mk,
             chain.map_to_fun, function.comp_app, exists_imp_distrib, not_forall],
end

end not_below

open Scott (hiding is_open)
open omega_complete_partial_order

lemma is_ωSup_ωSup {α} [omega_complete_partial_order α] (c : chain α) :
  is_ωSup c (ωSup c) :=
begin
  split,
  { apply le_ωSup, },
  { apply ωSup_le, },
end

lemma Scott_continuous_of_continuous {α β}
  [omega_complete_partial_order α]
  [omega_complete_partial_order β]
  (f : Scott α → Scott β) (hf : continuous f) :
  omega_complete_partial_order.continuous' f :=
begin
  simp only [continuous_def, (⁻¹')] at hf,
  have h : monotone f,
  { intros x y h,
    cases (hf {x | ¬ x ≤ f y} (not_below_is_open _)) with hf hf', clear hf',
    specialize hf h, simp only [set.preimage, set_of, (∈), set.mem, le_iff_imp] at hf,
    by_contradiction H, apply hf H (le_refl (f y)) },
  existsi h, intro c,
  apply eq_of_forall_ge_iff, intro z,
  specialize (hf _ (not_below_is_open z)),
  cases hf, specialize hf_h c,
  simp only [not_below, preorder_hom.coe_fun_mk, eq_iff_iff, set.mem_set_of_eq] at hf_h,
  rw [← not_iff_not],
  simp only [ωSup_le_iff, hf_h, ωSup, supr, Sup, complete_lattice.Sup, complete_semilattice_Sup.Sup,
    exists_prop, set.mem_range, preorder_hom.coe_fun_mk, chain.map_to_fun, function.comp_app,
    eq_iff_iff, not_forall],
  tauto,
end

lemma continuous_of_Scott_continuous {α β}
  [omega_complete_partial_order α]
  [omega_complete_partial_order β]
  (f : Scott α → Scott β) (hf : omega_complete_partial_order.continuous' f) :
  continuous f :=
begin
  rw continuous_def,
  intros s hs,
  change continuous' (s ∘ f),
  cases hs with hs hs',
  cases hf with hf hf',
  apply continuous.of_bundled,
  apply continuous_comp _ _ hf' hs',
end


/-
Copyright (c) 2019 Neil Strickland. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Neil Strickland

(This is part of an attempt to formalise some material from
 a basic undergraduate combinatorics course.)

 A "domino" means a subset of ℕ × ℕ of the form
 {i} × {j,j+1} or {i,i+1} × {j}.  Given a finite subset
 B ⊆ ℕ × ℕ, we ask whether B can be written as a disjoint
 union of dominos.  One basic tool that we can use is the
 chessboard colouring map c : ℕ × ℕ → {black,white}.
 (Probably it is more convenient to use bool = {ff,tt}
 instead of {black,white}.)  If B can be covered by a
 disjoint set of dominos, then it is clear that the
 number of black squares in B must be equal to the number
 of white squares.   Examples should be given to show that
 the converse fails.
-/

import data.fintype.basic algebra.group algebra.big_operators.basic tactic.ring

namespace combinatorics

lemma finset.mem_pair {α : Type} [decidable_eq α] {u v w : α} :
 u ∈ [v,w].to_finset ↔ u = v ∨ u = w :=
by { intros, simp }

lemma finset.pair_eq  {α : Type} [decidable_eq α] {u v w x : α} :
 [u,v].to_finset = [w,x].to_finset ↔
   (u = w ∧ v = x) ∨ (u = x ∧ v = w) :=
begin
  split,
  { intro h,
    have hu : u ∈ [u,v].to_finset := by simp,
    have hv : v ∈ [u,v].to_finset := by simp,
    have hw : w ∈ [w,x].to_finset := by simp,
    have hx : x ∈ [w,x].to_finset := by simp,
    rw [  h, finset.mem_pair] at hu hv,
    rw [← h, finset.mem_pair] at hw hx,
    cases hu with hu hu; cases hu;
    cases hv with hv hv; cases hv;
    cases hw with hw hw; cases hw;
    cases hx with hx hx; cases hx;
    try { left , exact ⟨rfl,rfl⟩ } ;
    try { right, exact ⟨rfl,rfl⟩ } },
  { intro h,
    cases h with h h; rcases h with ⟨⟨h₀⟩,⟨h₁⟩⟩,
    { refl },
    { ext z, rw[finset.mem_pair, finset.mem_pair],
      split; exact or.symm } }
end

lemma finset.pair_disjoint {α : Type} [decidable_eq α] {u v w x : α} :
  disjoint [u,v].to_finset [w,x].to_finset ↔
  (u ≠ w ∧ u ≠ x ∧ v ≠ w ∧ v ≠ x) :=
begin
  rw [disjoint_iff], change _ ∩ _ = ∅ ↔ _,
  rw [finset.eq_empty_iff_forall_not_mem],
  split,
  { intro h,
    have hu := h u, have hv := h v,
    have hw := h w, have hx := h x,
    rw [finset.mem_inter, finset.mem_pair, finset.mem_pair,
        decidable.not_and_iff_or_not,
        decidable.not_or_iff_and_not,decidable.not_or_iff_and_not]
         at hu hv hw hx,
    tauto },
  { rintro ⟨h₀,h₁,h₂,h₃⟩ a ha,
    rw [ finset.mem_inter, finset.mem_pair, finset.mem_pair ] at ha,
    cases ha with ha₀ ha₁,
    cases ha₀ with ha₀ ha₀; cases ha₀;
    cases ha₁ with ha₁ ha₁; cases ha₁;
    contradiction }
end

lemma prod.ne {α β : Type*} [decidable_eq α] [decidable_eq β]
  (a a' : α) (b b' : β) :
  prod.mk a b ≠ prod.mk a' b' ↔ (a ≠ a' ∨ b ≠ b') :=
begin
  rw [ne,prod.eq_iff_fst_eq_snd_eq, decidable.not_and_iff_or_not]
end

lemma mem_list_union {α : Type*} [decidable_eq α] {a : α} {l : list (finset α)} :
  a ∈ l.foldr has_union.union ∅ ↔ ∃ s, s ∈ l ∧ a ∈ s :=
begin
  induction l with s l ih,
  { rw [list.foldr], split; intro h,
    { exfalso, exact finset.not_mem_empty a h },
    { rcases h with ⟨s,hs⟩, exfalso, exact list.not_mem_nil s hs.left } },
  { rw [list.foldr, finset.mem_union], split; intro h,
    { cases h,
      { use s, exact ⟨list.mem_cons_self s l,h⟩ },
      { rcases (ih.mp h) with ⟨t,ht⟩,
        use t, exact ⟨list.mem_cons_of_mem s ht.left, ht.right⟩ } },
    { rcases h with ⟨t,ht⟩,
      rcases (list.mem_cons_iff t s l).mp ht.left with ⟨⟨_⟩|ht⟩ ,
      { left, exact ht.right },
      { right, exact ih.mpr ⟨t,⟨h,ht.right⟩⟩ } } }
end

namespace chess

def square := ℕ × ℕ

namespace square

lemma eq_iff {u v : square} : u = v ↔ u.1 = v.1 ∧ u.2 = v.2 :=
prod.eq_iff_fst_eq_snd_eq

def rank : square → ℕ := λ u, u.1 + u.2
def color : square → bool := λ u, u.rank.bodd

def hstep : square → square := λ u, ⟨u.1 + 1,u.2⟩
def vstep : square → square := λ u, ⟨u.1,u.2 + 1⟩

lemma hstep_eq (u v : square) : u.hstep = v.hstep ↔ u = v :=
begin
  cases u with i j, cases v with k l, rw [eq_iff, eq_iff],
  change i + 1 = k + 1 ∧ j = l ↔ i = k ∧ j = l,
  rw [nat.succ_inj']
end

lemma vstep_eq (u v : square) : u.vstep = v.vstep ↔ u = v :=
begin
  cases u with i j, cases v with k l, rw [eq_iff, eq_iff],
  change i = k ∧ j + 1 = l + 1 ↔ i = k ∧ j = l,
  rw [nat.succ_inj']
end

lemma hstep_ne_self (u : square) : u.hstep ≠ u := λ h,
by { rw[eq_iff] at h, exact nat.succ_ne_self _ h.1 }

lemma vstep_ne_self (u : square) : u.vstep ≠ u := λ h,
by { rw[eq_iff] at h, exact nat.succ_ne_self _ h.2 }

lemma rank_vstep (u : square) : u.vstep.rank = u.rank + 1 := rfl
lemma rank_hstep (u : square) : u.hstep.rank = u.rank + 1 :=  nat.succ_add _ _

lemma color_vstep (u : square) : u.vstep.color = bnot u.color :=
  by { simp only [color], rw [rank_vstep, nat.bodd_succ] }

lemma color_hstep (u : square) : u.hstep.color = bnot u.color :=
  by { simp only [color], rw [rank_hstep, nat.bodd_succ] }

end square

def count_pair := bool → ℕ

namespace count_pair

instance : add_comm_monoid count_pair :=
 by {unfold count_pair, pi_instance, }

def both : count_pair
| _ := 1

def delta : bool → count_pair
| ff ff := 1
| ff tt := 0
| tt ff := 0
| tt tt := 1

def delta' (n : ℕ) : count_pair := delta n.bodd

def tot : count_pair →+ ℕ := {
  to_fun := λ x, (x ff) + (x tt),
  map_zero' := rfl,
  map_add' := λ u v,
   begin
    change ((u ff) + (v ff)) + ((u tt) + (v tt)) =
           ((u ff) + (u tt)) + ((v ff) + (v tt)),
    rw[add_assoc,← add_assoc (v ff)],
    rw[add_comm (v ff) (u tt),add_assoc,add_assoc],
   end
}

lemma tot_both : tot both = 2 := rfl

lemma tot_delta : ∀ b : bool, tot (delta b) = 1
| ff := rfl
| tt := rfl

lemma delta_succ (b : bool) : (delta b) + (delta (bnot b)) = both :=
by { ext x, cases b; cases x; refl }

lemma delta'_succ (n : ℕ) : (delta' n) + (delta' n.succ) = both :=
by { dsimp [delta'], rw [nat.bodd_succ], exact delta_succ n.bodd }

lemma tot_delta' (n : ℕ) : tot (delta' n) = 1 := tot_delta n.bodd

def diff : count_pair →+ ℤ := {
 to_fun := λ x, (x tt) - (x ff),
 map_zero' := rfl,
 map_add' := λ u v,
 begin
  have : (u + v) tt = (u tt) + (v tt) := rfl, rw[this,int.coe_nat_add],
  have : (u + v) ff = (u ff) + (v ff) := rfl, rw[this,int.coe_nat_add],
  ring,
 end
}

lemma diff_both : diff both = 0 := rfl

end count_pair

open chess

def color_count (s : finset square) : count_pair :=
 s.sum (λ x, (count_pair.delta x.color))

def black_count (s : finset square) : ℕ := color_count s ff

def white_count (s : finset square) : ℕ := color_count s tt

def color_diff (s : finset (ℕ × ℕ)) : ℤ := (color_count s).diff

lemma count_eq (s : finset (ℕ × ℕ)) :
 (color_count s).tot = s.card :=
begin
 rw[color_count,count_pair.tot.map_sum],
 have : (λ x : square, (count_pair.delta x.color).tot) = (λ x, 1) :=
  by {funext, apply count_pair.tot_delta},
 rw[this,finset.sum_const,smul_eq_mul,mul_one]
end

namespace color_count

lemma empty : color_count ∅ = 0 := by {rw[color_count,finset.sum_empty]}

lemma sum (s t : finset square) :
 (color_count (s ∪ t)) + (color_count (s ∩ t)) =
 (color_count s) + (color_count t) :=
  finset.sum_union_inter

lemma disjoint_sum (s t : finset (ℕ × ℕ)) (h : disjoint s t) :
 (color_count (s ∪ t)) = (color_count s) + (color_count t) :=
   finset.sum_union h

lemma disjoint_sum' (ss : list (finset (ℕ × ℕ)))
 (h : ss.pairwise disjoint) :
  color_count (ss.foldr has_union.union ∅) = (ss.map color_count).sum :=
begin
  induction ss with s ss ih,
  { refl },
  { let t := ss.foldr has_union.union ∅,
    rw [list.pairwise_cons] at h,
    rw [list.foldr, list.map, list.sum_cons, ← ih h.right],
    apply disjoint_sum s t, rw [disjoint_iff],
    change s ∩ t = ∅, apply finset.eq_empty_of_forall_not_mem,
    intros x hx,
    replace hx := finset.mem_inter.mp hx,
    rcases mem_list_union.mp hx.right with ⟨u,hu⟩,
    have hx' := finset.mem_inter.mpr ⟨hx.1,hu.2⟩,
    have hsu : s ∩ u = ∅ := disjoint_iff.mp (h.left u hu.left),
    rw [hsu] at hx', exact finset.not_mem_empty x hx' }
end

end color_count

end chess

open chess

inductive domino : Type
| horizontal : square → domino
| vertical : square → domino

namespace domino

def to_list : domino → list square
| (horizontal u) := [u, u.hstep]
| (vertical   u) := [u, u.vstep]

lemma to_list_length (d : domino) :
  d.to_list.length = 2 := by { cases d; refl }

lemma to_list_nodup (d : domino) : d.to_list.nodup :=
begin
  cases d with u u; simp [to_list, list.nodup_cons],
  exact u.hstep_ne_self.symm, exact u.vstep_ne_self.symm
end

def to_finset (d : domino) : finset square :=
  ⟨d.to_list,d.to_list_nodup⟩

lemma to_list_coe (d : domino) :
  d.to_finset = d.to_list.to_finset := list.to_finset_eq d.to_list_nodup

lemma color_count (d : domino) :
  color_count d.to_finset = count_pair.both :=
begin
  rw [chess.color_count],
  rw [finset.sum_eq_multiset_sum d.to_finset
       (count_pair.delta ∘ square.color)],
  have : d.to_finset.val = d.to_list := rfl,
  rw [this, multiset.coe_map, multiset.coe_sum],
  cases d with u u;
  rw [to_list, list.map_cons, list.map_singleton,
      list.sum_cons, list.sum_cons, list.sum_nil, add_zero];
  rw [function.comp_app, function.comp_app],
  rw [square.color_hstep, count_pair.delta_succ],
  rw [square.color_vstep, count_pair.delta_succ]
end

lemma color_diff (d : domino) : (chess.color_count d.to_finset).diff = 0 :=
 by { rw[color_count],refl }

def overlap : domino → domino → Prop
| (horizontal u) (horizontal v) := u = v ∨ u = v.hstep ∨ u.hstep = v
| (horizontal u) (vertical v)   := u = v ∨ u = v.vstep ∨ u.hstep = v ∨ u.hstep = v.vstep
| (vertical u) (horizontal v)   := u = v ∨ u = v.hstep ∨ u.vstep = v ∨ u.vstep = v.hstep
| (vertical u) (vertical v)     := u = v ∨ u = v.vstep ∨ u.vstep = v

instance overlap_dec : decidable_rel overlap :=
 λ a b, by {cases a with u u; cases b with v v;
            rw[overlap]; apply_instance}

def disjoint : domino → domino → Prop :=
 λ a b , ¬ (overlap a b)

instance disjoint_dec : decidable_rel disjoint :=
 λ a b, by {dsimp[disjoint],apply_instance}

lemma disjoint_iff {a b : domino} :
 disjoint a b ↔ _root_.disjoint a.to_finset b.to_finset  :=
begin
  cases a with u u; cases b with v v;
  simp only [disjoint, to_list_coe, to_list, finset.pair_disjoint, ne];
  rw [overlap];
  try { rw[square.hstep_eq] at * }; try { rw[square.vstep_eq] at * };
  tauto
end

def track (l : list domino) := (l.map to_finset).foldr has_union.union ∅

def is_cover (s : finset (ℕ × ℕ)) (l : list domino) :=
  l.pairwise disjoint ∧ (track l) = s

def has_cover (s : finset (ℕ × ℕ)) := ∃ l, is_cover s l

lemma diff_eq_zero_aux (l : list domino) :
 (((l.map to_finset).map chess.color_count).map count_pair.diff).sum = 0 :=
begin
 induction l with d l0 ih,
 {refl},
 { rw[list.map_cons,list.map_cons,list.map_cons,color_diff,list.sum_cons,ih,add_zero] }
end

lemma diff_eq_zero {l : list domino}
  (hl : l.pairwise disjoint) :
      (chess.color_count (track l)).diff = 0 :=
begin
  let h₀ := list.pairwise.imp
    (λ a b,(@disjoint_iff a b).mp) hl,
  let h₁ := (list.pairwise_map to_finset).mpr h₀,
  let h₂ : (chess.color_count (track l)) = _ :=
   chess.color_count.disjoint_sum' (l.map to_finset) h₁,
  rw[h₂,count_pair.diff.map_list_sum,diff_eq_zero_aux],
end

end domino
end combinatorics


import tactic --hide

-- Level name : The `exfalso` tactic.

/-
In this level we want to prove prove that `false` implies any proposition `P`.

-/

/-Hint : Hint
You can do this using only `intro` and `cases`.
-/

/-Lemma
If $P$ is a logical statement then $\mathrm{false}$ implies $P$.
-/
lemma false_imp_P (P : Prop) : false → P :=
begin
 intro h,
 cases h,

end

/-Hint : What is going on here?
One way to solve this level is to use `intro h` followed by `cases h`.  Notice that using `intro h`,
introduces the assumption `h : false`. Lean thinks of `false` as empty, i.e having no elements.
`cases h` goes through each element in `h` and tries to prove our goal.
But since our assumption is `false` there are no cases, so the result is trivially true.
To make sense of this outside of Lean, we think that starting from a false statement we can have
any outcome, both true and false (see levels 3 & 4 of "True and False" world).

-/

/-
## The `exfalso` tactic

A way to use this result in Lean is with the <mark style ="background-color : #ebdef0 "> `exfalso`</mark> tactic,
which changes any goal to `false`.
-/

/-Tactic : exfalso
This changes any goal to `false`.
-/


import Lean4Axiomatic.Integer

namespace Lean4Axiomatic.Integer.Impl

/-! ## Implementation of fundamental definitions and properties of integers -/

/-! ### Formal difference representation of integers -/

/--
The formal (as in "having the form of") difference between two values of the
same type.

The field names suggest an interpretation for this structure of a starting
value (`init`) that has a quantity (`take`) removed from it. The structure then
denotes the value of the result.

Equivalently, this structure can be viewed as measuring the "directed gap"
between the two values. Specifically, it denotes the value that, when combined
with `take`, gives the result `init`.

Given a type of natural numbers `ℕ`, integers can be defined as values of
`Difference ℕ` under an equivalence relation that considers two differences to
be equal when they denote the same value according to an interpretation above.
-/
structure Difference (α : Type) : Type :=
  init : α
  take : α

infix:90 "——" => Difference.mk

namespace Difference

/--
Create a `Difference` from an ordered pair of values.

**Named parameters**
- `α`: The type of both elements of the ordered pair.
-/
def from_prod {α : Type} : α × α → Difference α
| (x, y) => x——y

variable {ℕ : Type}
variable [Natural ℕ]

/-! ### Equivalence -/

/--
The equivalence relation that separates all `Difference ℕ` values into buckets
denoting integers.

In other words, given two differences `d₁` and `d₂`, they represent the same
integer if and only if `eqv d₁ d₂` holds.

**Definition intuition**: Equating two differences means that they represent
the same quantity after subtraction; i.e., after their `take` values have been
removed from their `init` values. The subtracted values can be removed from the
equation without changing its correctness by adding each of them to both sides.
Doing that produces the expression that is the definition of this relation.
-/
def eqv : Difference ℕ → Difference ℕ → Prop
| a——b, c——d => a + d ≃ c + b

-- This is an instance so the operator can be used in the rest of the file
instance tildeDash : Operators.TildeDash (Difference ℕ) := {
  tildeDash := eqv
}

/--
The equivalence relation on differences is reflexive.

**Proof intuition**: The underlying equality in the equivalence relation is
symmetric in terms of the two differences; when both differences are the same,
the equality is trivial.
-/
theorem refl {a : Difference ℕ} : a ≃ a := by
  revert a; intro (a₁——a₂)
  show a₁ + a₂ ≃ a₁ + a₂
  exact Rel.refl

/--
The equivalence relation on differences is symmetric.

**Proof intuition**: The underlying equality in the equivalence relation is
already symmetric in terms of the two differences.
-/
theorem symm {a b : Difference ℕ} : a ≃ b → b ≃ a := by
  revert a; intro (a₁——a₂); revert b; intro (b₁——b₂)
  intro (_ : a₁ + b₂ ≃ b₁ + a₂)
  show b₁ + a₂ ≃ a₁ + b₂
  exact Rel.symm ‹a₁ + b₂ ≃ b₁ + a₂›

/--
The equivalence relation on differences is transitive.

**Proof intuition**: Add the underlying equalities of the two hypotheses; this
nearly produces the goal equality, but both sides have an extra `b₂ + b₁`. Use
the cancellation property of natural number addition to remove it.

The bulk of the proof is just the algebra needed to prepare for cancellation.
-/
theorem trans {a b c : Difference ℕ} : a ≃ b → b ≃ c → a ≃ c := by
  revert a; intro (a₁——a₂); revert b; intro (b₁——b₂); revert c; intro (c₁——c₂)
  intro (_ : a₁ + b₂ ≃ b₁ + a₂) (_ : b₁ + c₂ ≃ c₁ + b₂)
  show a₁ + c₂ ≃ c₁ + a₂
  have : (a₁ + c₂) + (b₂ + b₁) ≃ (c₁ + a₂) + (b₂ + b₁) := calc
    (a₁ + c₂) + (b₂ + b₁) ≃ _ := AA.expr_xxfxxff_lr_swap_rl
    (a₁ + b₂) + (c₂ + b₁) ≃ _ := AA.substL ‹a₁ + b₂ ≃ b₁ + a₂›
    (b₁ + a₂) + (c₂ + b₁) ≃ _ := AA.substL AA.comm
    (a₂ + b₁) + (c₂ + b₁) ≃ _ := AA.substR AA.comm
    (a₂ + b₁) + (b₁ + c₂) ≃ _ := AA.substR ‹b₁ + c₂ ≃ c₁ + b₂›
    (a₂ + b₁) + (c₁ + b₂) ≃ _ := AA.comm
    (c₁ + b₂) + (a₂ + b₁) ≃ _ := AA.expr_xxfxxff_lr_swap_rl
    (c₁ + a₂) + (b₂ + b₁) ≃ _ := Rel.refl
  exact AA.cancelR ‹(a₁ + c₂) + (b₂ + b₁) ≃ (c₁ + a₂) + (b₂ + b₁)›

instance eqvOp : Relation.Equivalence.EqvOp (Difference ℕ) := {
  toTildeDash := tildeDash
  refl := refl
  symm := symm
  trans := trans
}

/--
Conversion of ordered pairs into `Difference`s preserves equivalence.

**Proof intuition**: Equivalence of ordered pairs is stricter than equivalence
of differences. For ordered pairs, both the left and right elements must be
equivalent; for differences, any values representing the same gap are
equivalent. Thus one only needs to show that the former is strong enough to
imply the latter.
-/
instance from_prod_substitutive
    : AA.Substitutive₁ (α := ℕ × ℕ) from_prod (· ≃ ·) (· ≃ ·)
    := by
  apply AA.Substitutive₁.mk
  intro p q; revert p; intro ((n, m)); revert q; intro ((k, j))
  intro (_ : (n, m) ≃ (k, j))
  show from_prod (n, m) ≃ from_prod (k, j)
  show n——m ≃ k——j
  show n + j ≃ k + m
  have (And.intro (_ : n ≃ k) (_ : m ≃ j)) :=
    Relation.Equivalence.Impl.Prod.eqv_defn.mp ‹(n, m) ≃ (k, j)›
  calc
    n + j ≃ _ := AA.substL ‹n ≃ k›
    k + j ≃ _ := AA.substR (Rel.symm ‹m ≃ j›)
    k + m ≃ _ := Rel.refl

instance equivalence : Equivalence (Difference ℕ) := {
  eqvOp := eqvOp
}

/-! ### Conversion -/

/--
Every natural number can be represented as a difference.

**Definition intuition**: Taking nothing away from a natural number preserves
its value.
-/
instance from_natural : Coe ℕ (Difference ℕ) := {
  coe := (·——0)
}

/--
The conversion operation from natural numbers to differences respects
equivalence of natural numbers: if two natural numbers are equivalent they will
also be equivalent as differences.

**Property intuition**: This must be true if we want the conversion operation
to be a legitimate function `ℕ → Difference ℕ`.

**Proof intuition**: Viewing differences as pairs, the proof follows directly
from the substitution property on pairs.
-/
theorem from_ℕ_subst {n₁ n₂ : ℕ} : n₁ ≃ n₂ → (↑n₁ : Difference ℕ) ≃ ↑n₂ := by
  intro (_ : n₁ ≃ n₂)
  show n₁——0 ≃ n₂——0
  show from_prod (n₁, 0) ≃ from_prod (n₂, 0)
  apply AA.subst₁
  show (n₁, 0) ≃ (n₂, 0)
  exact AA.substL ‹n₁ ≃ n₂›

def from_natural_substitutive
    : AA.Substitutive₁ (α := ℕ) (β := Difference ℕ) (↑·) (· ≃ ·) (· ≃ ·)
    := {
  subst₁ := from_ℕ_subst
}

/--
If we know that two differences converted from natural numbers are equivalent,
then we also know that they came from the same natural numbers: the conversion
operation is one-to-one, i.e. injective.

**Property intuition**: We know intuitively that the natural numbers correspond
to the nonnegative integers. This property ensures that's the case, by
requiring the conversion operation to assign a unique difference to every
natural number.

**Proof intuition**: The result follows from the "reversibility" of the
conversion operation: it acts on each natural number in the same way, so that
obtaining the original natural numbers from the resulting differences is easy.
-/
theorem from_ℕ_inject {n₁ n₂ : ℕ} : (↑n₁ : Difference ℕ) ≃ ↑n₂ → n₁ ≃ n₂ := by
  intro (_ : n₁——0 ≃ n₂——0)
  show n₁ ≃ n₂
  have : n₁ + 0 ≃ n₂ + 0 := ‹n₁——0 ≃ n₂——0›
  calc
    n₁     ≃ _ := Rel.symm AA.identR
    n₁ + 0 ≃ _ := ‹n₁ + 0 ≃ n₂ + 0›
    n₂ + 0 ≃ _ := AA.identR
    n₂     ≃ _ := Rel.refl

instance from_natural_injective
    : AA.Injective (α := ℕ) (β := Difference ℕ) (↑·) (· ≃ ·) (· ≃ ·)
    := {
  inject := from_ℕ_inject
}

instance conversion : Conversion (ℕ := ℕ) (Difference ℕ) := {
  from_natural := from_natural
  from_natural_injective := from_natural_injective
  from_natural_substitutive := from_natural_substitutive
}

instance core : Core (ℕ := ℕ) (Difference ℕ) := Core.mk

end Difference

end Lean4Axiomatic.Integer.Impl


/-
Copyright (c) 2020 Anne Baanen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anne Baanen, Kexing Ying, Eric Wieser
-/
import linear_algebra.quadratic_form.basic
import analysis.special_functions.pow

/-!
# Quadratic forms over the complex numbers

`equivalent_sum_squares`: A nondegenerate quadratic form over the complex numbers is equivalent to
a sum of squares.

-/

namespace quadratic_form

open_locale big_operators
open finset

variables {ι : Type*} [fintype ι]

/-- The isometry between a weighted sum of squares on the complex numbers and the
sum of squares, i.e. `weighted_sum_squares` with weights 1 or 0. -/
noncomputable def isometry_sum_squares [decidable_eq ι] (w' : ι → ℂ) :
  isometry (weighted_sum_squares ℂ w')
    (weighted_sum_squares ℂ (λ i, if w' i = 0 then 0 else 1 : ι → ℂ)) :=
begin
  let w := λ i, if h : w' i = 0 then (1 : units ℂ) else units.mk0 (w' i) h,
  have hw' : ∀ i : ι, (w i : ℂ) ^ - (1 / 2 : ℂ) ≠ 0,
  { intros i hi,
    exact (w i).ne_zero ((complex.cpow_eq_zero_iff _ _).1 hi).1 },
  convert (weighted_sum_squares ℂ w').isometry_basis_repr
    ((pi.basis_fun ℂ ι).units_smul (λ i, (is_unit_iff_ne_zero.2 $ hw' i).unit)),
  ext1 v,
  erw [basis_repr_apply, weighted_sum_squares_apply, weighted_sum_squares_apply],
  refine sum_congr rfl (λ j hj, _),
  have hsum : (∑ (i : ι), v i • ((is_unit_iff_ne_zero.2 $ hw' i).unit : ℂ) •
    (pi.basis_fun ℂ ι) i) j = v j • w j ^ - (1 / 2 : ℂ),
  { rw [finset.sum_apply, sum_eq_single j, pi.basis_fun_apply, is_unit.unit_spec,
        linear_map.std_basis_apply, pi.smul_apply, pi.smul_apply, function.update_same,
        smul_eq_mul, smul_eq_mul, smul_eq_mul, mul_one],
    intros i _ hij,
    rw [pi.basis_fun_apply, linear_map.std_basis_apply, pi.smul_apply, pi.smul_apply,
        function.update_noteq hij.symm, pi.zero_apply, smul_eq_mul, smul_eq_mul,
        mul_zero, mul_zero],
    intro hj', exact false.elim (hj' hj) },
  simp_rw basis.units_smul_apply,
  erw [hsum, smul_eq_mul],
  split_ifs,
  { simp only [h, zero_smul, zero_mul]},
  have hww' : w' j = w j,
  { simp only [w, dif_neg h, units.coe_mk0] },
  simp only [hww', one_mul],
  change v j * v j = ↑(w j) * ((v j * ↑(w j) ^ -(1 / 2 : ℂ)) * (v j * ↑(w j) ^ -(1 / 2 : ℂ))),
  suffices : v j * v j = w j ^ - (1 / 2 : ℂ) * w j ^ - (1 / 2 : ℂ) * w j * v j * v j,
  { rw [this], ring },
  rw [← complex.cpow_add _ _ (w j).ne_zero, show - (1 / 2 : ℂ) + - (1 / 2) = -1, by ring,
      complex.cpow_neg_one, inv_mul_cancel (w j).ne_zero, one_mul],
end

/-- The isometry between a weighted sum of squares on the complex numbers and the
sum of squares, i.e. `weighted_sum_squares` with weight `λ i : ι, 1`. -/
noncomputable def isometry_sum_squares_units [decidable_eq ι] (w : ι → units ℂ) :
  isometry (weighted_sum_squares ℂ w) (weighted_sum_squares ℂ (1 : ι → ℂ)) :=
begin
  have hw1 : (λ i, if (w i : ℂ) = 0 then 0 else 1 : ι → ℂ) = 1,
  { ext i : 1, exact dif_neg (w i).ne_zero },
  have := isometry_sum_squares (coe ∘ w),
  rw hw1 at this,
  exact this,
end

/-- A nondegenerate quadratic form on the complex numbers is equivalent to
the sum of squares, i.e. `weighted_sum_squares` with weight `λ i : ι, 1`. -/
theorem equivalent_sum_squares {M : Type*} [add_comm_group M] [module ℂ M]
  [finite_dimensional ℂ M] (Q : quadratic_form ℂ M) (hQ : (associated Q).nondegenerate) :
  equivalent Q (weighted_sum_squares ℂ (1 : fin (finite_dimensional.finrank ℂ M) → ℂ)) :=
let ⟨w, ⟨hw₁⟩⟩ := Q.equivalent_weighted_sum_squares_units_of_nondegenerate' hQ in
  ⟨hw₁.trans (isometry_sum_squares_units w)⟩

end quadratic_form


/-
Copyright (c) 2022 Sébastien Gouëzel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
import analysis.calculus.bump_function_inner
import analysis.calculus.series
import analysis.convolution
import data.set.pointwise.support
import measure_theory.measure.haar_lebesgue

/-!
# Bump functions in finite-dimensional vector spaces

Let `E` be a finite-dimensional real normed vector space. We show that any open set `s` in `E` is
exactly the support of a smooth function taking values in `[0, 1]`,
in `is_open.exists_smooth_support_eq`.

Then we use this construction to construct bump functions with nice behavior, by convolving
the indicator function of `closed_ball 0 1` with a function as above with `s = ball 0 D`.
-/

noncomputable theory

open set metric topological_space function asymptotics measure_theory finite_dimensional
continuous_linear_map filter measure_theory.measure
open_locale pointwise topology nnreal big_operators convolution

variables {E : Type*} [normed_add_comm_group E]

section

variables [normed_space ℝ E] [finite_dimensional ℝ E]

/-- If a set `s` is a neighborhood of `x`, then there exists a smooth function `f` taking
values in `[0, 1]`, supported in `s` and with `f x = 1`. -/
theorem exists_smooth_tsupport_subset {s : set E} {x : E} (hs : s ∈ 𝓝 x) :
  ∃ (f : E → ℝ), tsupport f ⊆ s ∧ has_compact_support f ∧ cont_diff ℝ ⊤ f ∧
    range f ⊆ Icc 0 1 ∧ f x = 1 :=
begin
  obtain ⟨d, d_pos, hd⟩ : ∃ (d : ℝ) (hr : 0 < d), euclidean.closed_ball x d ⊆ s,
    from euclidean.nhds_basis_closed_ball.mem_iff.1 hs,
  let c : cont_diff_bump (to_euclidean x) :=
  { r := d/2,
    R := d,
    r_pos := half_pos d_pos,
    r_lt_R := half_lt_self d_pos },
  let f : E → ℝ := c ∘ to_euclidean,
  have f_supp : f.support ⊆ euclidean.ball x d,
  { assume y hy,
    have : to_euclidean y ∈ function.support c,
      by simpa only [f, function.mem_support, function.comp_app, ne.def] using hy,
    rwa c.support_eq at this },
  have f_tsupp : tsupport f ⊆ euclidean.closed_ball x d,
  { rw [tsupport, ← euclidean.closure_ball _ d_pos.ne'],
    exact closure_mono f_supp },
  refine ⟨f, f_tsupp.trans hd, _, _, _, _⟩,
  { refine is_compact_of_is_closed_bounded is_closed_closure _,
    have : bounded (euclidean.closed_ball x d), from euclidean.is_compact_closed_ball.bounded,
    apply this.mono _,
    refine (is_closed.closure_subset_iff euclidean.is_closed_closed_ball).2 _,
    exact f_supp.trans euclidean.ball_subset_closed_ball },
  { apply c.cont_diff.comp,
    exact continuous_linear_equiv.cont_diff _ },
  { rintros t ⟨y, rfl⟩,
    exact ⟨c.nonneg, c.le_one⟩ },
  { apply c.one_of_mem_closed_ball,
    apply mem_closed_ball_self,
    exact (half_pos d_pos).le }
end

/-- Given an open set `s` in a finite-dimensional real normed vector space, there exists a smooth
function with values in `[0, 1]` whose support is exactly `s`. -/
theorem is_open.exists_smooth_support_eq {s : set E} (hs : is_open s) :
  ∃ (f : E → ℝ), f.support = s ∧ cont_diff ℝ ⊤ f ∧ set.range f ⊆ set.Icc 0 1 :=
begin
  /- For any given point `x` in `s`, one can construct a smooth function with support in `s` and
  nonzero at `x`. By second-countability, it follows that we may cover `s` with the supports of
  countably many such functions, say `g i`.
  Then `∑ i, r i • g i` will be the desired function if `r i` is a sequence of positive numbers
  tending quickly enough to zero. Indeed, this ensures that, for any `k ≤ i`, the `k`-th derivative
  of `r i • g i` is bounded by a prescribed (summable) sequence `u i`. From this, the summability
  of the series and of its successive derivatives follows. -/
  rcases eq_empty_or_nonempty s with rfl|h's,
  { exact ⟨(λ x, 0), function.support_zero, cont_diff_const,
      by simp only [range_const, singleton_subset_iff, left_mem_Icc, zero_le_one]⟩ },
  let ι := {f : E → ℝ // f.support ⊆ s ∧ has_compact_support f ∧ cont_diff ℝ ⊤ f ∧
    range f ⊆ Icc 0 1},
  obtain ⟨T, T_count, hT⟩ : ∃ T : set ι, T.countable ∧ (⋃ f ∈ T, support (f : E → ℝ)) = s,
  { have : (⋃ (f : ι), (f : E → ℝ).support) = s,
    { refine subset.antisymm (Union_subset (λ f, f.2.1)) _,
      assume x hx,
      rcases exists_smooth_tsupport_subset (hs.mem_nhds hx) with ⟨f, hf⟩,
      let g : ι := ⟨f, (subset_tsupport f).trans hf.1, hf.2.1, hf.2.2.1, hf.2.2.2.1⟩,
      have : x ∈ support (g : E → ℝ),
        by simp only [hf.2.2.2.2, subtype.coe_mk, mem_support, ne.def, one_ne_zero, not_false_iff],
      exact mem_Union_of_mem _ this },
    simp_rw ← this,
    apply is_open_Union_countable,
    rintros ⟨f, hf⟩,
    exact hf.2.2.1.continuous.is_open_support },
  obtain ⟨g0, hg⟩ : ∃ (g0 : ℕ → ι), T = range g0,
  { apply countable.exists_eq_range T_count,
    rcases eq_empty_or_nonempty T with rfl|hT,
    { simp only [Union_false, Union_empty] at hT,
      simp only [←hT, not_nonempty_empty] at h's,
      exact h's.elim },
    { exact hT } },
  let g : ℕ → E → ℝ := λ n, (g0 n).1,
  have g_s : ∀ n, support (g n) ⊆ s := λ n, (g0 n).2.1,
  have s_g : ∀ x ∈ s, ∃ n, x ∈ support (g n),
  { assume x hx,
    rw ← hT at hx,
    obtain ⟨i, iT, hi⟩ : ∃ (i : ι) (hi : i ∈ T), x ∈ support (i : E → ℝ),
      by simpa only [mem_Union] using hx,
    rw [hg, mem_range] at iT,
    rcases iT with ⟨n, hn⟩,
    rw ← hn at hi,
    exact ⟨n, hi⟩ },
  have g_smooth : ∀ n, cont_diff ℝ ⊤ (g n) := λ n, (g0 n).2.2.2.1,
  have g_comp_supp : ∀ n, has_compact_support (g n) := λ n, (g0 n).2.2.1,
  have g_nonneg : ∀ n x, 0 ≤ g n x,
    from λ n x, ((g0 n).2.2.2.2 (mem_range_self x)).1,
  obtain ⟨δ, δpos, c, δc, c_lt⟩ :
    ∃ (δ : ℕ → ℝ≥0), (∀ (i : ℕ), 0 < δ i) ∧ ∃ (c : nnreal), has_sum δ c ∧ c < 1,
    from nnreal.exists_pos_sum_of_countable one_ne_zero ℕ,
  have : ∀ (n : ℕ), ∃ (r : ℝ),
    0 < r ∧ ∀ i ≤ n, ∀ x, ‖iterated_fderiv ℝ i (r • g n) x‖ ≤ δ n,
  { assume n,
    have : ∀ i, ∃ R, ∀ x, ‖iterated_fderiv ℝ i (λ x, g n x) x‖ ≤ R,
    { assume i,
      have : bdd_above (range (λ x, ‖iterated_fderiv ℝ i (λ (x : E), g n x) x‖)),
      { apply ((g_smooth n).continuous_iterated_fderiv le_top).norm
          .bdd_above_range_of_has_compact_support,
        apply has_compact_support.comp_left _ norm_zero,
        apply (g_comp_supp n).iterated_fderiv },
      rcases this with ⟨R, hR⟩,
      exact ⟨R, λ x, hR (mem_range_self _)⟩ },
    choose R hR using this,
    let M := max (((finset.range (n+1)).image R).max' (by simp)) 1,
    have M_pos : 0 < M := zero_lt_one.trans_le (le_max_right _ _),
    have δnpos : 0 < δ n := δpos n,
    have IR : ∀ i ≤ n, R i ≤ M,
    { assume i hi,
      refine le_trans _ (le_max_left _ _),
      apply finset.le_max',
      apply finset.mem_image_of_mem,
      simp only [finset.mem_range],
      linarith },
    refine ⟨M⁻¹ * δ n, by positivity, λ i hi x, _⟩,
    calc ‖iterated_fderiv ℝ i ((M⁻¹ * δ n) • g n) x‖
        = ‖(M⁻¹ * δ n) • iterated_fderiv ℝ i (g n) x‖ :
      by { rw iterated_fderiv_const_smul_apply, exact (g_smooth n).of_le le_top }
    ... = M⁻¹ * δ n * ‖iterated_fderiv ℝ i (g n) x‖ :
      by { rw [norm_smul, real.norm_of_nonneg], positivity }
    ... ≤ M⁻¹ * δ n * M :
      mul_le_mul_of_nonneg_left ((hR i x).trans (IR i hi)) (by positivity)
    ... = δ n : by field_simp [M_pos.ne'] },
  choose r rpos hr using this,
  have S : ∀ x, summable (λ n, (r n • g n) x),
  { assume x,
    refine summable_of_nnnorm_bounded _ δc.summable (λ n, _),
    rw [← nnreal.coe_le_coe, coe_nnnorm],
    simpa only [norm_iterated_fderiv_zero] using hr n 0 (zero_le n) x },
  refine ⟨λ x, (∑' n, (r n • g n) x), _, _, _⟩,
  { apply subset.antisymm,
    { assume x hx,
      simp only [pi.smul_apply, algebra.id.smul_eq_mul, mem_support, ne.def] at hx,
      contrapose! hx,
      have : ∀ n, g n x = 0,
      { assume n,
        contrapose! hx,
        exact g_s n hx },
      simp only [this, mul_zero, tsum_zero] },
    { assume x hx,
      obtain ⟨n, hn⟩ : ∃ n, x ∈ support (g n), from s_g x hx,
      have I : 0 < r n * g n x,
        from mul_pos (rpos n) (lt_of_le_of_ne (g_nonneg n x) (ne.symm hn)),
      exact ne_of_gt (tsum_pos (S x) (λ i, mul_nonneg (rpos i).le (g_nonneg i x)) n I) } },
  { refine cont_diff_tsum_of_eventually (λ n, (g_smooth n).const_smul _)
      (λ k hk, (nnreal.has_sum_coe.2 δc).summable) _,
    assume i hi,
    simp only [nat.cofinite_eq_at_top, pi.smul_apply, algebra.id.smul_eq_mul,
      filter.eventually_at_top, ge_iff_le],
    exact ⟨i, λ n hn x, hr _ _ hn _⟩ },
  { rintros - ⟨y, rfl⟩,
    refine ⟨tsum_nonneg (λ n, mul_nonneg (rpos n).le (g_nonneg n y)), le_trans _ c_lt.le⟩,
    have A : has_sum (λ n, (δ n : ℝ)) c, from nnreal.has_sum_coe.2 δc,
    rw ← A.tsum_eq,
    apply tsum_le_tsum _ (S y) A.summable,
    assume n,
    apply (le_abs_self _).trans,
    simpa only [norm_iterated_fderiv_zero] using hr n 0 (zero_le n) y }
end

end

section

namespace exists_cont_diff_bump_base

/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces.
It is the characteristic function of the closed unit ball. -/
def φ : E → ℝ := (closed_ball (0 : E) 1).indicator (λ y, (1 : ℝ))

variables [normed_space ℝ E]  [finite_dimensional ℝ E]

section helper_definitions

variable (E)
lemma u_exists : ∃ u : E → ℝ, cont_diff ℝ ⊤ u ∧
  (∀ x, u x ∈ Icc (0 : ℝ) 1) ∧ (support u = ball 0 1) ∧ (∀ x, u (-x) = u x) :=
begin
  have A : is_open (ball (0 : E) 1), from is_open_ball,
  obtain ⟨f, f_support, f_smooth, f_range⟩ :
    ∃ (f : E → ℝ), f.support = ball (0 : E) 1 ∧ cont_diff ℝ ⊤ f ∧ set.range f ⊆ set.Icc 0 1,
    from A.exists_smooth_support_eq,
  have B : ∀ x, f x ∈ Icc (0 : ℝ) 1 := λ x, f_range (mem_range_self x),
  refine ⟨λ x, (f x + f (-x)) / 2, _, _, _, _⟩,
  { exact (f_smooth.add (f_smooth.comp cont_diff_neg)).div_const _ },
  { assume x,
    split,
    { linarith [(B x).1, (B (-x)).1] },
    { linarith [(B x).2, (B (-x)).2] } },
  { refine support_eq_iff.2 ⟨λ x hx, _, λ x hx, _⟩,
    { apply ne_of_gt,
      have : 0 < f x,
      { apply lt_of_le_of_ne (B x).1 (ne.symm _),
        rwa ← f_support at hx },
      linarith [(B (-x)).1] },
    { have I1 : x ∉ support f, by rwa f_support,
      have I2 : -x ∉ support f,
      { rw f_support,
        simp only at hx,
        simpa using hx },
      simp only [mem_support, not_not] at I1 I2,
      simp only [I1, I2, add_zero, zero_div] } },
  { assume x, simp only [add_comm, neg_neg] }
end

variable {E}

/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces,
which is smooth, symmetric, and with support equal to the unit ball. -/
def u (x : E) : ℝ := classical.some (u_exists E) x

variable (E)
lemma u_smooth : cont_diff ℝ ⊤ (u : E → ℝ) := (classical.some_spec (u_exists E)).1

lemma u_continuous : continuous (u : E → ℝ) := (u_smooth E).continuous

lemma u_support : support (u : E → ℝ) = ball 0 1 := (classical.some_spec (u_exists E)).2.2.1

lemma u_compact_support : has_compact_support (u : E → ℝ) :=
begin
  rw [has_compact_support_def, u_support, closure_ball (0 : E) one_ne_zero],
  exact is_compact_closed_ball _ _,
end
variable {E}

lemma u_nonneg (x : E) : 0 ≤ u x := ((classical.some_spec (u_exists E)).2.1 x).1

lemma u_le_one (x : E) : u x ≤ 1 := ((classical.some_spec (u_exists E)).2.1 x).2

lemma u_neg (x : E) : u (-x) = u x := (classical.some_spec (u_exists E)).2.2.2 x

variables [measurable_space E] [borel_space E]

local notation `μ` := measure_theory.measure.add_haar

variable (E)
lemma u_int_pos : 0 < ∫ (x : E), u x ∂μ :=
begin
  refine (integral_pos_iff_support_of_nonneg u_nonneg _).mpr _,
  { exact (u_continuous E).integrable_of_has_compact_support (u_compact_support E) },
  { rw u_support, exact measure_ball_pos _ _ zero_lt_one }
end
variable {E}

/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces,
which is smooth, symmetric, with support equal to the ball of radius `D` and integral `1`. -/
def W (D : ℝ) (x : E) : ℝ := ((∫ (x : E), u x ∂μ) * |D|^(finrank ℝ E))⁻¹ • u (D⁻¹ • x)

lemma W_def (D : ℝ) :
  (W D : E → ℝ) = λ x, ((∫ (x : E), u x ∂μ) * |D|^(finrank ℝ E))⁻¹ • u (D⁻¹ • x) :=
by { ext1 x, refl }

lemma W_nonneg (D : ℝ) (x : E) : 0 ≤ W D x :=
begin
  apply mul_nonneg _ (u_nonneg _),
  apply inv_nonneg.2,
  apply mul_nonneg (u_int_pos E).le,
  apply pow_nonneg (abs_nonneg D)
end

lemma W_mul_φ_nonneg (D : ℝ) (x y : E) : 0 ≤ W D y * φ (x - y) :=
mul_nonneg (W_nonneg D y) (indicator_nonneg (by simp only [zero_le_one, implies_true_iff]) _)

variable (E)

lemma W_integral {D : ℝ} (Dpos : 0 < D) : ∫ (x : E), W D x ∂μ = 1 :=
begin
  simp_rw [W, integral_smul],
  rw [integral_comp_inv_smul_of_nonneg μ (u : E → ℝ) Dpos.le,
    abs_of_nonneg Dpos.le, mul_comm],
  field_simp [Dpos.ne', (u_int_pos E).ne'],
end

lemma W_support {D : ℝ} (Dpos : 0 < D) : support (W D : E → ℝ) = ball 0 D :=
begin
  have B : D • ball (0 : E) 1 = ball 0 D,
    by rw [smul_unit_ball Dpos.ne', real.norm_of_nonneg Dpos.le],
  have C : D ^ finrank ℝ E ≠ 0, from pow_ne_zero _ Dpos.ne',
  simp only [W_def, algebra.id.smul_eq_mul, support_mul, support_inv, univ_inter,
    support_comp_inv_smul₀ Dpos.ne', u_support, B, support_const (u_int_pos E).ne',
    support_const C, abs_of_nonneg Dpos.le],
end

lemma W_compact_support {D : ℝ} (Dpos : 0 < D) : has_compact_support (W D : E → ℝ) :=
begin
  rw [has_compact_support_def, W_support E Dpos, closure_ball (0 : E) Dpos.ne'],
  exact is_compact_closed_ball _ _,
end
variable {E}

/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces.
It is the convolution between a smooth function of integral `1` supported in the ball of radius `D`,
with the indicator function of the closed unit ball. Therefore, it is smooth, equal to `1` on the
ball of radius `1 - D`, with support equal to the ball of radius `1 + D`. -/
def Y (D : ℝ) : E → ℝ := W D ⋆[lsmul ℝ ℝ, μ] φ

lemma Y_neg (D : ℝ) (x : E) : Y D (-x) = Y D x :=
begin
  apply convolution_neg_of_neg_eq,
  { apply eventually_of_forall (λ x, _),
    simp only [W_def, u_neg, smul_neg, algebra.id.smul_eq_mul, mul_eq_mul_left_iff,
      eq_self_iff_true, true_or], },
  { apply eventually_of_forall (λ x, _),
    simp only [φ, indicator, mem_closed_ball_zero_iff, norm_neg] },
end

lemma Y_eq_one_of_mem_closed_ball {D : ℝ} {x : E} (Dpos : 0 < D)
  (hx : x ∈ closed_ball (0 : E) (1 - D)) : Y D x = 1 :=
begin
  change (W D ⋆[lsmul ℝ ℝ, μ] φ) x = 1,
  have B : ∀ (y : E), y ∈ ball x D → φ y = 1,
  { have C : ball x D ⊆ ball 0 1,
    { apply ball_subset_ball',
      simp only [mem_closed_ball] at hx,
      linarith only [hx] },
    assume y hy,
    simp only [φ, indicator, mem_closed_ball, ite_eq_left_iff, not_le, zero_ne_one],
    assume h'y,
    linarith only [mem_ball.1 (C hy), h'y] },
  have Bx : φ x = 1, from B _ (mem_ball_self Dpos),
  have B' : ∀ y, y ∈ ball x D → φ y = φ x, by { rw Bx, exact B },
  rw convolution_eq_right' _ (le_of_eq (W_support E Dpos)) B',
  simp only [lsmul_apply, algebra.id.smul_eq_mul, integral_mul_right, W_integral E Dpos, Bx,
    one_mul],
end

lemma Y_nonneg (D : ℝ) (x : E) : 0 ≤ Y D x :=
integral_nonneg (W_mul_φ_nonneg D x)

lemma Y_le_one {D : ℝ} (x : E) (Dpos : 0 < D) : Y D x ≤ 1 :=
begin
  have A : (W D ⋆[lsmul ℝ ℝ, μ] φ) x ≤ (W D ⋆[lsmul ℝ ℝ, μ] 1) x,
  { apply convolution_mono_right_of_nonneg _ (W_nonneg D)
      (indicator_le_self' (λ x hx, zero_le_one)) (λ x, zero_le_one),
    refine (has_compact_support.convolution_exists_left _ (W_compact_support E Dpos) _
      (locally_integrable_const (1 : ℝ)) x).integrable,
    exact continuous_const.mul ((u_continuous E).comp (continuous_id.const_smul _)) },
  have B : (W D ⋆[lsmul ℝ ℝ, μ] (λ y, (1 : ℝ))) x = 1,
    by simp only [convolution, continuous_linear_map.map_smul, mul_inv_rev, coe_smul', mul_one,
      lsmul_apply, algebra.id.smul_eq_mul, integral_mul_left, W_integral E Dpos, pi.smul_apply],
  exact A.trans (le_of_eq B)
end

lemma Y_pos_of_mem_ball {D : ℝ} {x : E} (Dpos : 0 < D) (D_lt_one : D < 1)
  (hx : x ∈ ball (0 : E) (1 + D)) : 0 < Y D x :=
begin
  simp only [mem_ball_zero_iff] at hx,
  refine (integral_pos_iff_support_of_nonneg (W_mul_φ_nonneg D x) _).2 _,
  { have F_comp : has_compact_support (W D),
      from W_compact_support E Dpos,
    have B : locally_integrable (φ : E → ℝ) μ,
      from (locally_integrable_const _).indicator measurable_set_closed_ball,
    have C : continuous (W D : E → ℝ),
      from continuous_const.mul ((u_continuous E).comp (continuous_id.const_smul _)),
    exact (has_compact_support.convolution_exists_left (lsmul ℝ ℝ : ℝ →L[ℝ] ℝ →L[ℝ] ℝ)
      F_comp C B x).integrable },
  { set z := (D / (1 + D)) • x with hz,
    have B : 0 < 1 + D, by linarith,
    have C : ball z (D * (1 + D- ‖x‖) / (1 + D)) ⊆ support (λ (y : E), W D y * φ (x - y)),
    { assume y hy,
      simp only [support_mul, W_support E Dpos],
      simp only [φ, mem_inter_iff, mem_support, ne.def, indicator_apply_eq_zero,
        mem_closed_ball_zero_iff, one_ne_zero, not_forall, not_false_iff, exists_prop, and_true],
      split,
      { apply ball_subset_ball' _ hy,
        simp only [z, norm_smul, abs_of_nonneg Dpos.le, abs_of_nonneg B.le, dist_zero_right,
          real.norm_eq_abs, abs_div],
        simp only [div_le_iff B] with field_simps,
        ring_nf },
      { have ID : ‖D / (1 + D) - 1‖ = 1 / (1 + D),
        { rw real.norm_of_nonpos,
          { simp only [B.ne', ne.def, not_false_iff, mul_one, neg_sub, add_tsub_cancel_right]
              with field_simps},
          { simp only [B.ne', ne.def, not_false_iff, mul_one] with field_simps,
            apply div_nonpos_of_nonpos_of_nonneg _ B.le,
            linarith only, } },
        rw ← mem_closed_ball_iff_norm',
        apply closed_ball_subset_closed_ball' _ (ball_subset_closed_ball hy),
        rw [← one_smul ℝ x, dist_eq_norm, hz, ← sub_smul, one_smul, norm_smul, ID],
        simp only [-one_div, -mul_eq_zero, B.ne', div_le_iff B] with field_simps,
        simp only [mem_ball_zero_iff] at hx,
        nlinarith only [hx, D_lt_one] } },
    apply lt_of_lt_of_le _ (measure_mono C),
    apply measure_ball_pos,
    exact div_pos (mul_pos Dpos (by linarith only [hx])) B }
end

variable (E)

lemma Y_smooth : cont_diff_on ℝ ⊤ (uncurry Y) ((Ioo (0 : ℝ) 1) ×ˢ (univ : set E)) :=
begin
  have hs : is_open (Ioo (0 : ℝ) (1 : ℝ)), from is_open_Ioo,
  have hk : is_compact (closed_ball (0 : E) 1), from proper_space.is_compact_closed_ball _ _,
  refine cont_diff_on_convolution_left_with_param (lsmul ℝ ℝ) hs hk _ _ _,
  { rintros p x hp hx,
    simp only [W, mul_inv_rev, algebra.id.smul_eq_mul, mul_eq_zero, inv_eq_zero],
    right,
    contrapose! hx,
    have : p⁻¹ • x ∈ support u, from mem_support.2 hx,
    simp only [u_support, norm_smul, mem_ball_zero_iff, real.norm_eq_abs, abs_inv,
      abs_of_nonneg hp.1.le, ← div_eq_inv_mul, div_lt_one hp.1] at this,
    rw mem_closed_ball_zero_iff,
    exact this.le.trans hp.2.le },
  { exact (locally_integrable_const _).indicator measurable_set_closed_ball },
  { apply cont_diff_on.mul,
    { refine (cont_diff_on_const.mul _).inv
        (λ x hx, ne_of_gt (mul_pos (u_int_pos E) (pow_pos (abs_pos_of_pos hx.1.1) _))),
      apply cont_diff_on.pow,
      simp_rw [← real.norm_eq_abs],
      apply @cont_diff_on.norm ℝ,
      { exact cont_diff_on_fst },
      { assume x hx, exact ne_of_gt hx.1.1 } },
    { apply (u_smooth E).comp_cont_diff_on,
      exact cont_diff_on.smul (cont_diff_on_fst.inv (λ x hx, ne_of_gt hx.1.1)) cont_diff_on_snd } },
end

lemma Y_support {D : ℝ} (Dpos : 0 < D) (D_lt_one : D < 1) :
  support (Y D : E → ℝ) = ball (0 : E) (1 + D) :=
support_eq_iff.2 ⟨λ x hx, (Y_pos_of_mem_ball Dpos D_lt_one hx).ne',
  λ x hx, Y_eq_zero_of_not_mem_ball Dpos hx⟩

variable {E}

end helper_definitions

@[priority 100]
instance {E : Type*} [normed_add_comm_group E] [normed_space ℝ E] [finite_dimensional ℝ E] :
  has_cont_diff_bump E :=
begin
  refine ⟨⟨_⟩⟩,
  borelize E,
  have IR : ∀ (R : ℝ), 1 < R → 0 < (R - 1) / (R + 1),
  { assume R hR, apply div_pos; linarith },
  exact
  { to_fun := λ R x, if 1 < R then Y ((R - 1) / (R + 1)) (((R + 1) / 2)⁻¹ • x) else 0,
    mem_Icc := λ R x, begin
      split_ifs,
      { refine ⟨Y_nonneg _ _, Y_le_one _ (IR R h)⟩ },
      { simp only [pi.zero_apply, left_mem_Icc, zero_le_one] }
    end,
    symmetric := λ R x, begin
      split_ifs,
      { simp only [Y_neg, smul_neg] },
      { refl },
    end,
    smooth := begin
      suffices : cont_diff_on ℝ ⊤
        ((uncurry Y) ∘ (λ (p : ℝ × E), ((p.1 - 1) / (p.1 + 1), ((p.1 + 1)/2)⁻¹ • p.2)))
        (Ioi 1 ×ˢ univ),
      { apply this.congr,
        rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
        simp only [hR, uncurry_apply_pair, if_true, comp_app], },
      apply (Y_smooth E).comp,
      { apply cont_diff_on.prod,
        { refine (cont_diff_on_fst.sub cont_diff_on_const).div
            (cont_diff_on_fst.add cont_diff_on_const) _,
          rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
          apply ne_of_gt,
          dsimp only,
          linarith, },
        { apply cont_diff_on.smul _ cont_diff_on_snd,
          refine ((cont_diff_on_fst.add cont_diff_on_const).div_const _).inv _,
          rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
          apply ne_of_gt,
          dsimp only,
          linarith } },
      { rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
        have A : 0 < (R - 1) / (R + 1), by { apply div_pos; linarith },
        have B :  (R - 1) / (R + 1) < 1, by { apply (div_lt_one _ ).2; linarith },
        simp only [mem_preimage, prod_mk_mem_set_prod_eq, mem_Ioo, mem_univ, and_true, A, B] }
    end,
    eq_one := λ R hR x hx, begin
      have A : 0 < R + 1, by linarith,
      simp only [hR, if_true],
      apply Y_eq_one_of_mem_closed_ball (IR R hR),
      simp only [norm_smul, inv_div, mem_closed_ball_zero_iff, real.norm_eq_abs, abs_div,
                 abs_two, abs_of_nonneg A.le],
      calc 2 / (R + 1) * ‖x‖ ≤ 2 / (R + 1) * 1 :
        mul_le_mul_of_nonneg_left hx (div_nonneg zero_le_two A.le)
      ... = 1 - (R - 1) / (R + 1) : by { field_simp [A.ne'], ring }
    end,
    support := λ R hR, begin
      have A : 0 < (R + 1) / 2, by linarith,
      have A' : 0 < R + 1, by linarith,
      have C :  (R - 1) / (R + 1) < 1, by { apply (div_lt_one _ ).2; linarith },
      simp only [hR, if_true, support_comp_inv_smul₀ A.ne', Y_support _ (IR R hR) C,
        smul_ball A.ne', real.norm_of_nonneg A.le, smul_zero],
      congr' 1,
      field_simp [A'.ne'],
      ring,
    end },
end

end exists_cont_diff_bump_base

end


/-
Copyright (c) 2022 Pierre-Alexandre Bazin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Pierre-Alexandre Bazin
-/
import linear_algebra.dfinsupp
import ring_theory.ideal.operations

/-!
# An additional lemma about coprime ideals

This lemma generalises `exists_sum_eq_one_iff_pairwise_coprime` to the case of non-principal ideals.
It is on a separate file due to import requirements.
-/

namespace ideal
variables {ι R : Type*} [comm_semiring R]

/--A finite family of ideals is pairwise coprime (that is, any two of them generate the whole ring)
iff when taking all the possible intersections of all but one of these ideals, the resulting family
of ideals still generate the whole ring.

For example with three ideals : `I ⊔ J = I ⊔ K = J ⊔ K = ⊤ ↔ (I ⊓ J) ⊔ (I ⊓ K) ⊔ (J ⊓ K) = ⊤`.

When ideals are all of the form `I i = R ∙ s i`, this is equivalent to the
`exists_sum_eq_one_iff_pairwise_coprime` lemma.-/
lemma supr_infi_eq_top_iff_pairwise {t : finset ι} (h : t.nonempty) (I : ι → ideal R) :
  (⨆ i ∈ t, ⨅ j (hj : j ∈ t) (ij : j ≠ i), I j) = ⊤ ↔
    (t : set ι).pairwise (λ i j, I i ⊔ I j = ⊤) :=
begin
  haveI : decidable_eq ι := classical.dec_eq ι,
  rw [eq_top_iff_one, submodule.mem_supr_finset_iff_exists_sum],
  refine h.cons_induction _ _; clear' t h,
  { simp only [finset.sum_singleton, finset.coe_singleton, set.pairwise_singleton, iff_true],
    refine λ a, ⟨λ i, if h : i = a then ⟨1, _⟩ else 0, _⟩,
    { rw h, simp only [finset.mem_singleton, ne.def, infi_infi_eq_left, eq_self_iff_true,
        not_true, infi_false]},
    { simp only [dif_pos, dif_ctx_congr, submodule.coe_mk, eq_self_iff_true] } },
  intros a t hat h ih,
  rw [finset.coe_cons,
    set.pairwise_insert_of_symmetric (λ i j (h : I i ⊔ I j = ⊤), sup_comm.trans h)],
  split,
  { rintro ⟨μ, hμ⟩, rw finset.sum_cons at hμ,
    refine ⟨ih.mp ⟨pi.single h.some ⟨μ a, _⟩ + λ i, ⟨μ i, _⟩, _⟩, λ b hb ab, _⟩,
    { have := submodule.coe_mem (μ a), rw mem_infi at this ⊢,
      --for some reason `simp only [mem_infi]` times out
      intro i, specialize this i, rw [mem_infi, mem_infi] at this ⊢,
      intros hi _, apply this (finset.subset_cons _ hi),
      rintro rfl, exact hat hi },
    { have := submodule.coe_mem (μ i), simp only [mem_infi] at this ⊢,
      intros j hj ij, exact this _ (finset.subset_cons _ hj) ij },
    { rw [← @if_pos _ _ h.some_spec R (μ a) 0, ← finset.sum_pi_single',
        ← finset.sum_add_distrib] at hμ,
      convert hμ, ext i, rw [pi.add_apply, submodule.coe_add, submodule.coe_mk],
      by_cases hi : i = h.some,
      { rw [hi, pi.single_eq_same, pi.single_eq_same, submodule.coe_mk] },
      { rw [pi.single_eq_of_ne hi, pi.single_eq_of_ne hi, submodule.coe_zero] } },
    { rw [eq_top_iff_one, submodule.mem_sup],
      rw add_comm at hμ, refine ⟨_, _, _, _, hμ⟩,
      { refine sum_mem _ (λ x hx, _),
        have := submodule.coe_mem (μ x), simp only [mem_infi] at this,
        apply this _ (finset.mem_cons_self _ _), rintro rfl, exact hat hx },
      { have := submodule.coe_mem (μ a), simp only [mem_infi] at this,
        exact this _ (finset.subset_cons _ hb) ab.symm } } },
  { rintro ⟨hs, Hb⟩, obtain ⟨μ, hμ⟩ := ih.mpr hs,
    obtain ⟨u, hu, v, hv, huv⟩ := submodule.mem_sup.mp
      ((eq_top_iff_one _).mp $ sup_infi_eq_top $ λ b hb, Hb b hb $ by { rintro rfl, exact hat hb }),
    refine ⟨λ i, if hi : i = a then ⟨v, _⟩ else ⟨u * μ i, _⟩, _⟩,
    { simp only [mem_infi] at hv ⊢,
      intros j hj ij, rw [finset.mem_cons, ← hi] at hj,
      exact hv _ (hj.resolve_left ij) },
    { have := submodule.coe_mem (μ i), simp only [mem_infi] at this ⊢,
      intros j hj ij,
      rcases finset.mem_cons.mp hj with rfl | hj,
      { exact mul_mem_right _ _ hu },
      { exact mul_mem_left _ _ (this _ hj ij) } },
    { rw [finset.sum_cons, dif_pos rfl, add_comm],
      rw ← mul_one u at huv, rw [← huv, ← hμ, finset.mul_sum],
      congr' 1, apply finset.sum_congr rfl, intros j hj,
      rw dif_neg, refl,
      rintro rfl, exact hat hj } }
end

end ideal


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

! This file was ported from Lean 3 source module algebra.order.sub.with_top
! leanprover-community/mathlib commit afdb4fa3b32d41106a4a09b371ce549ad7958abd
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Order.Sub.Defs
import Mathbin.Algebra.Order.Monoid.WithTop

/-!
# Lemma about subtraction in ordered monoids with a top element adjoined.

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

variable {α β : Type _}

namespace WithTop

section

variable [Sub α] [Zero α]

#print WithTop.sub /-
/-- If `α` has subtraction and `0`, we can extend the subtraction to `with_top α`. -/
protected def sub : ∀ a b : WithTop α, WithTop α
  | _, ⊤ => 0
  | ⊤, (x : α) => ⊤
  | (x : α), (y : α) => (x - y : α)
#align with_top.sub WithTop.sub
-/

instance : Sub (WithTop α) :=
  ⟨WithTop.sub⟩

#print WithTop.coe_sub /-
@[simp, norm_cast]
theorem coe_sub {a b : α} : (↑(a - b) : WithTop α) = ↑a - ↑b :=
  rfl
#align with_top.coe_sub WithTop.coe_sub
-/

#print WithTop.top_sub_coe /-
@[simp]
theorem top_sub_coe {a : α} : (⊤ : WithTop α) - a = ⊤ :=
  rfl
#align with_top.top_sub_coe WithTop.top_sub_coe
-/

#print WithTop.sub_top /-
@[simp]
theorem sub_top {a : WithTop α} : a - ⊤ = 0 := by cases a <;> rfl
#align with_top.sub_top WithTop.sub_top
-/

#print WithTop.sub_eq_top_iff /-
@[simp]
theorem sub_eq_top_iff : ∀ {a b : WithTop α}, a - b = ⊤ ↔ a = ⊤ ∧ b ≠ ⊤
  | _, ⊤ => by simp
  | ⊤, (b : α) => by simp
  | (a : α), (b : α) => by simp only [← coe_sub, coe_ne_top, false_and_iff]
#align with_top.sub_eq_top_iff WithTop.sub_eq_top_iff
-/

#print WithTop.map_sub /-
theorem map_sub [Sub β] [Zero β] {f : α → β} (h : ∀ x y, f (x - y) = f x - f y) (h₀ : f 0 = 0) :
    ∀ x y : WithTop α, (x - y).map f = x.map f - y.map f
  | _, ⊤ => by simp only [h₀, sub_top, WithTop.map_zero, coe_zero, map_top]
  | ⊤, (x : α) => rfl
  | (x : α), (y : α) => by simp only [← coe_sub, map_coe, h]
#align with_top.map_sub WithTop.map_sub
-/

end

variable [CanonicallyOrderedAddMonoid α] [Sub α] [OrderedSub α]

instance : OrderedSub (WithTop α) := by
  constructor
  rintro x y z
  induction y using WithTop.recTopCoe; · simp
  induction x using WithTop.recTopCoe; · simp
  induction z using WithTop.recTopCoe; · simp
  norm_cast; exact tsub_le_iff_right

end WithTop


import mynat.definition
import mynat.mul

namespace mynat

lemma zero_mul (m : mynat) : 0 * m = 0 :=
begin [nat_num_game]
    induction m with d hd,
    {
        rw mul_zero,
        refl,
    },
    {
        rw mul_succ,
        rw add_zero,
        exact hd,
    },
end

end mynat