import pseudo_normed_group.category.CompHausFiltPseuNormGrp

universe variables u

open category_theory
open_locale nnreal

local attribute [instance] type_pow

noncomputable theory

/-- The category of CompHaus-ly filtered pseudo-normed groups with exhaustive filtrations
and with strict morphisms. -/
structure CompHausFiltPseuNormGrp₁ : Type (u+1) :=
(M : Type u)
[str : comphaus_filtered_pseudo_normed_group M]
(exhaustive' : ∀ m : M, ∃ c, m ∈ pseudo_normed_group.filtration M c)

namespace CompHausFiltPseuNormGrp₁

instance : has_coe_to_sort CompHausFiltPseuNormGrp₁ Type* := ⟨λ M, M.M⟩
instance (M : CompHausFiltPseuNormGrp₁) : comphaus_filtered_pseudo_normed_group M := M.str

lemma exhaustive (M : CompHausFiltPseuNormGrp₁) (m : M) :
  ∃ c, m ∈ pseudo_normed_group.filtration M c := M.exhaustive' _

instance : large_category CompHausFiltPseuNormGrp₁.{u} :=
{ hom := λ A B, strict_comphaus_filtered_pseudo_normed_group_hom A B,
  id := λ A, strict_comphaus_filtered_pseudo_normed_group_hom.id,
  comp := λ A B C f g, g.comp f }

/-- The "forget ₁" functor from `CompHaus`-ly filtered normed groups with strict morphisms,
  to CompHaus-ly filtered pseudo-normed groups with bounded morphisms, which is the
  identity on objects. -/
@[simps]
def _root_.CHFPNG₁_to_CHFPNGₑₗ : CompHausFiltPseuNormGrp₁ ⥤ CompHausFiltPseuNormGrp :=
{ obj := λ M, CompHausFiltPseuNormGrp.of M,
  map := λ M₁ M₂ f, f.to_chfpsng_hom }

instance : faithful (CHFPNG₁_to_CHFPNGₑₗ.{u}) :=
{ map_injective' := λ M₁ M₂ f g h,
  by { ext x, apply_fun (λ φ, φ.to_fun) at h, exact congr_fun h x } }

instance : concrete_category CompHausFiltPseuNormGrp₁.{u} :=
{ forget :=
  { obj := λ M, M.M,
    map := λ A B f, f },
  forget_faithful := ⟨⟩ } .

def level : ℝ≥0 ⥤ CompHausFiltPseuNormGrp₁.{u} ⥤ CompHaus :=
{ obj := λ c,
  { obj := λ M, CompHaus.of $ pseudo_normed_group.filtration M c,
    map := λ A B f, ⟨_, f.level_continuous _⟩ },
  map := λ c₁ c₂ h,
    { app := λ M, by letI : fact (c₁ ≤ c₂) := ⟨le_of_hom h⟩; exact
        ⟨_, comphaus_filtered_pseudo_normed_group.continuous_cast_le _ _⟩ } } .

section limits

/-!
In this section, we show (hopefully ;)) that `CompHausFiltPseuNormGrp₁` has limits.
-/

variables {J : Type u} [small_category J] (G : J ⥤ CompHausFiltPseuNormGrp₁.{u})

open pseudo_normed_group
open category_theory.limits

/-- This is a bifunctor which associates to each `c : ℝ≥0` and `j : J`,
  the `c`-th term of the filtration of `G.obj j`. -/
def cone_point_diagram : as_small.{u} ℝ≥0 ⥤ J ⥤ CompHaus.{u} :=
as_small.down ⋙ level ⋙ (whiskering_left _ _ _).obj G

@[derive [topological_space, t2_space]]
def cone_point_type_filt (c : ℝ≥0) : Type u :=
{ x : Π j : J, filtration (G.obj j) c | ∀ ⦃i j : J⦄ (e : i ⟶ j), (G.map e).level (x _) = x _ }

instance (c : ℝ≥0) : compact_space (cone_point_type_filt G c) :=
(CompHaus.limit_cone.{_ u} (((cone_point_diagram G).obj (as_small.up.obj c)))).X.is_compact -- ;-)

namespace cone_point_type_filt

variable {G}

instance (c : ℝ≥0) : has_coe_to_fun (cone_point_type_filt G c)
  (λ x, Π j : J, filtration (G.obj j) c) := ⟨λ x, x.1⟩

@[ext] lemma ext {c} (x y : cone_point_type_filt G c) :
  (⇑x : Π j : J, filtration (G.obj j) c) = y → x = y := subtype.ext

@[simp] lemma level_apply {c : ℝ≥0} {i j : J} (x : cone_point_type_filt G c) (e : i ⟶ j) :
  (G.map e).level (x i) = x j := x.2 e

@[simp] lemma map_apply {c : ℝ≥0} {i j : J} (x : cone_point_type_filt G c) (e : i ⟶ j) :
  (G.map e) (x i) = x j := by {rw ← (G.map e).coe_level, simp }

def trans {c₁ c₂ : ℝ≥0} (h : c₁ ≤ c₂) (x : cone_point_type_filt G c₁) : cone_point_type_filt G c₂ :=
⟨λ j, cast_le' h (x j), λ i j e, by { ext, simp }⟩

@[simp] lemma trans_apply {c₁ c₂ : ℝ≥0} (h : c₁ ≤ c₂) (x : cone_point_type_filt G c₁) (j : J) :
  x.trans h j = cast_le' h (x j) := by { ext, refl }

lemma trans_injective {c₁ c₂ : ℝ≥0} (h : c₁ ≤ c₂) :
  function.injective (trans h : cone_point_type_filt G c₁ → cone_point_type_filt G c₂) :=
begin
  intros x y hh,
  ext j,
  apply_fun (λ e, (e j : G.obj j)) at hh,
  exact hh
end

lemma trans_continuous {c₁ c₂ : ℝ≥0} (h : c₁ ≤ c₂) :
  continuous (trans h : cone_point_type_filt G c₁ → cone_point_type_filt G c₂) :=
begin
  -- ;-)
  let η := ((cone_point_diagram G).map (as_small.up.map $ hom_of_le $ h)),
  let hS := (CompHaus.limit_cone_is_limit.{_ u} (((cone_point_diagram G).obj (as_small.up.obj c₂)))),
  let T := (CompHaus.limit_cone.{_ u} (((cone_point_diagram G).obj (as_small.up.obj c₁)))),
  exact (hS.map T η).continuous,
end

lemma continuous_apply {c : ℝ≥0} (j : J) : continuous (λ t : cone_point_type_filt G c, t j) :=
begin
  change continuous ((λ u : Π j, filtration (G.obj j) c, u j) ∘
    (λ u : cone_point_type_filt G c, ⇑u)),
  apply continuous.comp,
  apply continuous_apply,
  apply continuous_subtype_coe,
end

instance {c} : has_zero (cone_point_type_filt G c) := has_zero.mk $
⟨λ j, 0, λ i j e, by { ext, dsimp, simp }⟩

instance {c} : has_neg (cone_point_type_filt G c) := has_neg.mk $ λ x,
⟨λ j, - (x j), λ i j e, by { ext, dsimp, simp, }⟩

def add' {c₁ c₂} (x : cone_point_type_filt G c₁) (y : cone_point_type_filt G c₂) :
  cone_point_type_filt G (c₁ + c₂) :=
⟨λ j, add' (x j, y j), λ i j e, by { ext, dsimp, simp, }⟩

@[simp] lemma zero_apply {c} (j : J) : (0 : cone_point_type_filt G c) j = 0 := rfl
@[simp] lemma neg_apply {c} (j : J) (x : cone_point_type_filt G c) : (-x) j = - (x j) := rfl
@[simp] lemma add'_apply_coe {c₁ c₂} (j : J) (x : cone_point_type_filt G c₁)
  (y : cone_point_type_filt G c₂) : ((x.add' y) j : G.obj j) = x j + y j := rfl

lemma continuous_neg {c} : continuous (λ x : cone_point_type_filt G c, - x) :=
begin
  apply continuous.subtype_mk,
  apply continuous_pi,
  intros j,
  change continuous ((λ x, -x) ∘ (λ a : cone_point_type_filt G c, (a j))),
  apply continuous.comp,
  apply comphaus_filtered_pseudo_normed_group.continuous_neg',
  apply continuous_apply,
end

lemma continuous_add' {c1 c2} :
  continuous (λ t : cone_point_type_filt G c1 × cone_point_type_filt G c2, t.1.add' t.2) :=
begin
  apply continuous.subtype_mk,
  apply continuous_pi,
  intros j,
  let A : cone_point_type_filt G c1 × cone_point_type_filt G c2 →
    (Π j : J, filtration (G.obj j) c1) × (Π j : J, filtration (G.obj j) c2) :=
    λ t, (t.1,t.2),
  let B : (Π j : J, filtration (G.obj j) c1) × (Π j : J, filtration (G.obj j) c2) →
    filtration (G.obj j) c1 × filtration (G.obj j) c2 := λ t, (t.1 j, t.2 j),
  let C : filtration (G.obj j) c1 × filtration (G.obj j) c2 → filtration (G.obj j) (c1 + c2) :=
    pseudo_normed_group.add',
  change continuous (C ∘ B ∘ A),
  apply continuous.comp,
  apply comphaus_filtered_pseudo_normed_group.continuous_add',
  apply continuous.comp,
  { apply continuous.prod_mk,
    { change continuous ((λ t : Π j : J, filtration (G.obj j) c1, t j) ∘ prod.fst),
      apply continuous.comp,
      apply _root_.continuous_apply,
      exact continuous_fst },
    { change continuous ((λ t : Π j : J, filtration (G.obj j) c2, t j) ∘ prod.snd),
      apply continuous.comp,
      apply _root_.continuous_apply,
      exact continuous_snd } },
  apply continuous.prod_map,
  apply continuous_subtype_coe,
  apply continuous_subtype_coe,
end

end cone_point_type_filt

def cone_point_type_setoid : setoid (Σ (c : ℝ≥0), cone_point_type_filt G c) :=
{ r := λ x y, ∃ (d : ℝ≥0) (hx : x.1 ≤ d) (hy : y.1 ≤ d), x.2.trans hx = y.2.trans hy,
  iseqv := begin
    refine ⟨_,_,_⟩,
    { rintro ⟨c,x⟩,
      use [c, le_refl _, le_refl _] },
    { rintro ⟨c,x⟩ ⟨d,y⟩ ⟨e,h1,h2,h⟩,
      dsimp at *,
      refine ⟨_, le_sup_left, le_sup_right, _⟩,
      ext j : 3,
      symmetry,
      apply_fun (λ e, (e j : G.obj j)) at h,
      exact h },
    { rintro ⟨c,x⟩ ⟨d,y⟩ ⟨e,z⟩ ⟨i,h1,hh1,hhh1⟩ ⟨j,h2,hh2,hhh2⟩,
      dsimp at *,
      refine ⟨_, le_sup_left, le_sup_right, _⟩,
      ext jj : 3,
      apply_fun (λ e, (e jj : G.obj jj)) at hhh1,
      apply_fun (λ e, (e jj : G.obj jj)) at hhh2,
      erw [hhh1, hhh2], refl },
  end }

def cone_point_type : Type u := quotient (cone_point_type_setoid G)

namespace cone_point_type
variable {G}

def incl (c : ℝ≥0) : cone_point_type_filt G c → cone_point_type G :=
quotient.mk' ∘ sigma.mk c

lemma incl_injective (c : ℝ≥0) :
  function.injective (incl c : cone_point_type_filt G c → cone_point_type G) :=
begin
  intros x y h,
  replace h := quotient.exact' h,
  obtain ⟨d,h1,h2,h⟩ := h,
  dsimp at h1 h2 h,
  rw (show h1 = h2, by refl) at h,
  apply cone_point_type_filt.trans_injective h2,
  exact h,
end

@[simp]
lemma incl_trans {c₁ c₂ : ℝ≥0} (h : c₁ ≤ c₂) (x : cone_point_type_filt G c₁) :
  incl _ (x.trans h) = incl _ x :=
begin
  apply quotient.sound',
  refine ⟨c₁ ⊔ c₂, by simp, by simp, _⟩,
  ext,
  refl,
end

lemma incl_jointly_surjective (x : cone_point_type G) :
  ∃ (c : ℝ≥0) (y : cone_point_type_filt G c), incl c y = x :=
begin
  rcases x,
  obtain ⟨c,y⟩ := x,
  use [c,y],
  refl,
end

def index (x : cone_point_type G) : ℝ≥0 := (incl_jointly_surjective x).some

def preimage (x : cone_point_type G) : cone_point_type_filt G x.index :=
  (incl_jointly_surjective x).some_spec.some

@[simp]
lemma preimage_spec (x : cone_point_type G) : incl _ x.preimage = x :=
  (incl_jointly_surjective x).some_spec.some_spec

@[simp]
lemma coe_incl_preimage_apply {c} (x : cone_point_type_filt G c) (j : J) :
  ((incl c x).preimage j : G.obj j) = x j :=
begin
  let e := c ⊔ (incl c x).index,
  change _ = (cast_le' le_sup_left (x j) : G.obj j),
  rw ← cone_point_type_filt.trans_apply (le_sup_left : _ ≤ e) x j,
  rw ← coe_cast_le' (le_sup_right : _ ≤ e),
  rw ← cone_point_type_filt.trans_apply,
  congr' 2,
  apply incl_injective,
  simp,
end

instance : has_zero (cone_point_type G) := ⟨incl 0 0⟩

lemma zero_def : (0 : cone_point_type G) = incl 0 0 := rfl

instance : has_neg (cone_point_type G) := has_neg.mk $
λ x, incl _ (-x.preimage)

lemma neg_def (x : cone_point_type G) : -x = incl _ (-x.preimage) := rfl

instance : has_add (cone_point_type G) := has_add.mk $
λ x y, incl _ (x.preimage.add' y.preimage)

lemma add_def (x y : cone_point_type G) : x + y = incl _ (x.preimage.add' y.preimage) := rfl

lemma incl_add_incl (c₁ c₂ : ℝ≥0)
  (x₁ : cone_point_type_filt G c₁) (x₂ : cone_point_type_filt G c₂) :
  (incl c₁ x₁) + (incl c₂ x₂) = (incl (c₁ + c₂) (x₁.add' x₂)) :=
begin
  rw add_def,
  apply quotient.sound',
  refine ⟨max _ _, le_max_left _ _, le_max_right _ _, _⟩,
  ext,
  simp only [cone_point_type_filt.trans_apply, cone_point_type_filt.add'_apply_coe,
    coe_cast_le, coe_incl_preimage_apply, coe_cast_le'],
end

lemma zero_add (x : cone_point_type G) : 0 + x = x :=
begin
  conv_rhs {rw ← x.preimage_spec},
  apply quotient.sound',
  refine ⟨(0 : cone_point_type G).index + x.index, by simp, by simp, _⟩,
  dsimp,
  ext j : 3,
  simp only [cone_point_type_filt.trans_apply, cone_point_type_filt.add'_apply_coe, coe_cast_le'],
  simp only [add_left_eq_self],
  apply coe_incl_preimage_apply,
end

lemma add_comm (x y : cone_point_type G) : x + y = y + x :=
begin
  apply quotient.sound',
  refine ⟨x.index + y.index, le_refl _, le_of_eq (by {dsimp, rw add_comm}), _⟩,
  dsimp,
  ext j : 3,
  simp only [cone_point_type_filt.trans_apply, cone_point_type_filt.add'_apply_coe,
    coe_cast_le, coe_cast_le'],
  rw add_comm,
end

lemma add_zero (x : cone_point_type G) : x + 0 = x := by { rw add_comm, apply zero_add }

lemma add_assoc (x y z : cone_point_type G) : x + y + z = x + (y + z) :=
begin
  apply quotient.sound',
  refine ⟨_, le_sup_left, le_sup_right, _⟩,
  dsimp,
  ext j : 3,
  simp only [cone_point_type_filt.trans_apply, cone_point_type_filt.add'_apply_coe,
    coe_cast_le, coe_cast_le'],
  erw [coe_incl_preimage_apply, coe_incl_preimage_apply],
  simp [add_assoc],
end

lemma add_left_neg (x : cone_point_type G) : -x + x = 0 :=
begin
  apply quotient.sound',
  refine ⟨_,le_sup_left, le_sup_right,_⟩,
  dsimp,
  ext j : 3,
  simp only [cone_point_type_filt.trans_apply, cone_point_type_filt.zero_apply,
    cone_point_type_filt.add'_apply_coe, coe_cast_le, filtration.coe_zero, coe_cast_le'],
  erw coe_incl_preimage_apply,
  simp,
end

instance : add_comm_group (cone_point_type G) :=
{ add_assoc := add_assoc,
  zero_add := zero_add,
  add_zero := add_zero,
  add_left_neg := add_left_neg,
  add_comm := add_comm,
  ..(infer_instance : has_add _),
  ..(infer_instance : has_zero _),
  ..(infer_instance : has_neg _) }

variable (G)
def filt (c : ℝ≥0) : set (cone_point_type G) := set.range (incl c)

def filt_equiv (c : ℝ≥0) : cone_point_type_filt G c ≃ filt G c :=
equiv.of_bijective (λ x, ⟨_, x, rfl⟩)
begin
  split,
  { intros x y h,
    apply_fun (λ e, e.val) at h,
    apply incl_injective,
    exact h },
  { rintro ⟨_,x,rfl⟩, use x }
end

instance {c} : topological_space (filt G c) :=
topological_space.induced (filt_equiv G c).symm infer_instance

def filt_homeo (c : ℝ≥0) : filt G c ≃ₜ cone_point_type_filt G c :=
homeomorph.homeomorph_of_continuous_open (filt_equiv G c).symm continuous_induced_dom
begin
  intros U hU,
  have : inducing (filt_equiv G c).symm := ⟨rfl⟩,
  rw this.is_open_iff at hU,
  obtain ⟨U,hU,rfl⟩ := hU,
  simpa,
end

instance {c} : compact_space (filt G c) :=
(filt_homeo G c).symm.compact_space

instance {c} : t2_space (filt G c) :=
(filt_homeo G c).symm.t2_space

def filt_iso (c : ℝ≥0) : CompHaus.of (filt G c) ≅
  (CompHaus.limit_cone.{_ u} (((cone_point_diagram G).obj (as_small.up.obj c)))).X :=
{ hom := (filt_homeo G c).to_continuous_map,
  inv := (filt_homeo G c).symm.to_continuous_map,
  hom_inv_id' := by { ext1, simp },
  inv_hom_id' := by { ext1, simp } }

variable {G}

@[simp] lemma incl_neg {c} (x : cone_point_type_filt G c) :
  incl c (-x) = - incl c x :=
begin
  apply quotient.sound',
  refine ⟨_, le_sup_left, le_sup_right, _⟩,
  dsimp,
  ext j : 3,
  simp,
end

@[simp] lemma incl_add' {c1 c2} (x1 : cone_point_type_filt G c1) (x2 : cone_point_type_filt G c2) :
  incl (c1 + c2) (x1.add' x2) = incl c1 x1 + incl c2 x2 :=
begin
  apply quotient.sound',
  refine ⟨_, le_sup_left, le_sup_right, _⟩,
  dsimp,
  ext j : 3,
  simp,
end

@[simp] lemma incl_zero {c} : incl c (0 : cone_point_type_filt G c) = 0 :=
begin
  apply quotient.sound',
  refine ⟨_, le_sup_left, le_sup_right, _⟩,
  dsimp,
  ext j : 3,
  simp,
end

instance : pseudo_normed_group (cone_point_type G) :=
{ filtration := filt G,
  filtration_mono := begin
    rintro c1 c2 h x ⟨x,rfl⟩,
    dsimp [filt],
    use x.trans h,
    simp,
  end,
  zero_mem_filtration := begin
    intro c,
    use 0,
    simp,
  end,
  neg_mem_filtration := begin
    rintros c x ⟨x,rfl⟩,
    use -x,
    simp,
  end,
  add_mem_filtration := begin
    rintros c1 c2 x1 x2 ⟨x1,rfl⟩ ⟨x2,rfl⟩,
    use x1.add' x2,
    simp,
  end }

instance : comphaus_filtered_pseudo_normed_group (cone_point_type G) :=
{ topology := by apply_instance,
  t2 := by apply_instance,
  compact := by apply_instance,
  continuous_add' := begin
    intros c1 c2,
    let E : filtration (cone_point_type G) c1 × filtration (cone_point_type G) c2 →
      cone_point_type_filt G c1 × cone_point_type_filt G c2 :=
      λ t, ⟨(filt_homeo G c1) t.1, (filt_homeo G c2) t.2⟩,
    let E' : cone_point_type_filt G c1 × cone_point_type_filt G c2 →
      filtration (cone_point_type G) c1 × filtration (cone_point_type G) c2 :=
      λ t, ⟨(filt_homeo G c1).symm t.1, (filt_homeo G c2).symm t.2⟩,
    have hE'E : E' ∘ E = id := by { dsimp [E,E'], ext, simp, simp },
    have : (filt_homeo G (c1 + c2)).symm ∘
      (λ t : cone_point_type_filt G c1 × cone_point_type_filt G c2, t.1.add' t.2) ∘ E = add',
    { suffices : add' ∘ E' = (filt_homeo G (c1 + c2)).to_equiv.symm ∘
        (λ t : cone_point_type_filt G c1 × cone_point_type_filt G c2, t.1.add' t.2),
      { erw [← function.comp.assoc, ← this, function.comp.assoc, hE'E],
        simp },
      dsimp only [filt_homeo, homeomorph.homeomorph_of_continuous_open, E'],
      ext,
      dsimp [filt_homeo, filt_equiv, E, E'],
      simp },
    rw ← this, clear this,
    apply continuous.comp (homeomorph.continuous _),
    apply continuous.comp,
    apply cone_point_type_filt.continuous_add',
    dsimp [E],
    continuity,
  end,
  continuous_neg' := begin
    intros c,
    have : (neg' : filtration (cone_point_type G) c → filtration (cone_point_type G) c) =
      (filt_homeo G c).symm ∘ (λ x, -x) ∘ filt_homeo G c,
    { suffices :
        (neg' : filtration (cone_point_type G) c → filtration (cone_point_type G) c) ∘
          (filt_homeo G c).to_equiv.symm = (filt_homeo G c).to_equiv.symm ∘ (λ x, -x),
      { erw [← function.comp.assoc, ← this, function.comp.assoc, equiv.symm_comp_self],
        simp },
      dsimp only [filt_homeo, homeomorph.homeomorph_of_continuous_open],
      simp only [equiv.symm_symm],
      ext,
      dsimp [filt_equiv],
      simp },
    rw this,
    simp [cone_point_type_filt.continuous_neg],
  end,
  continuous_cast_le := begin
    rintro c₁ c₂ ⟨h⟩,
    change continuous (cast_le' h),
    have : cast_le' h = (filt_homeo G c₂).symm ∘
      cone_point_type_filt.trans h ∘ (filt_homeo G c₁),
    { suffices : cast_le' h ∘ (filt_homeo G c₁).to_equiv.symm =
        (filt_homeo G c₂).to_equiv.symm ∘ cone_point_type_filt.trans h,
      { erw [← function.comp.assoc, ← this, function.comp.assoc, equiv.symm_comp_self],
        simp },
      dsimp only [filt_homeo, homeomorph.homeomorph_of_continuous_open],
      simp only [equiv.symm_symm],
      ext,
      dsimp [filt_equiv],
      simp },
    simp [this, cone_point_type_filt.trans_continuous],
  end }

end cone_point_type

def cone_point : CompHausFiltPseuNormGrp₁ :=
{ M := cone_point_type G,
  exhaustive' := cone_point_type.incl_jointly_surjective }

def proj (j : J) : cone_point G ⟶ G.obj j :=
{ to_fun := λ x, x.preimage j,
  map_zero' := begin
    rw cone_point_type.zero_def,
    simp only [cone_point_type.coe_incl_preimage_apply,
      cone_point_type_filt.zero_apply, filtration.coe_zero],
  end,
  map_add' := begin
    intros x y,
    rw cone_point_type.add_def x y,
    simp only [cone_point_type.coe_incl_preimage_apply,
      cone_point_type_filt.add'_apply_coe],
  end,
  strict' := begin
    rintros c x ⟨x,rfl⟩,
    simp only [cone_point_type.coe_incl_preimage_apply,
      subtype.coe_prop],
  end,
  continuous' := begin
    intros c,
    dsimp,
    let E : filtration (cone_point_type G) c → filtration (G.obj j) c :=
      λ t, ((cone_point_type.filt_homeo G c) t) j,
    suffices : continuous E,
    { convert this,
      ext ⟨t,t,rfl⟩,
      dsimp [E],
      simp only [cone_point_type.coe_incl_preimage_apply],
      congr' 2,
      apply_fun (cone_point_type.filt_homeo G c).symm,
      simp only [homeomorph.symm_apply_apply],
      ext, refl },
    dsimp [E],
    change continuous ((λ (u : cone_point_type_filt G c), u j) ∘ cone_point_type.filt_homeo G c),
    simp only [homeomorph.comp_continuous_iff'],
    apply cone_point_type_filt.continuous_apply,
  end } .

def limit_cone : cone G :=
{ X := cone_point G,
  π :=
  { app := λ j, proj G j,
    naturality' := begin
      intros i j e,
      ext,
      dsimp,
      simp only [comp_apply, category.id_comp],
      have := (cone_point_type.preimage x).2 e,
      apply_fun (λ e, (e : G.obj j)) at this,
      exact this.symm,
    end } }

def index {M : CompHausFiltPseuNormGrp₁} (x : M) : ℝ≥0 := (M.exhaustive x).some
def preimage {M : CompHausFiltPseuNormGrp₁} (x : M) : filtration M (index x) :=
  ⟨x,(M.exhaustive x).some_spec⟩

def limit_cone_lift_map (D : cone G) : D.X → cone_point G := λ x,
cone_point_type.incl (index x) ⟨λ j, (D.π.app j).level (preimage x), begin
  intros i j e,
  ext,
  dsimp,
  simp,
end⟩

lemma limit_cone_lift_map_map_zero {D : cone G} :
  limit_cone_lift_map G D 0 = 0 :=
begin
  apply quotient.sound',
  refine ⟨_, le_sup_left, le_sup_right, _⟩,
  dsimp,
  ext j,
  simp only [cone_point_type_filt.trans_apply, cone_point_type_filt.zero_apply,
    coe_cast_le, filtration.coe_zero, coe_cast_le'],
  apply (D.π.app j).map_zero,
end

lemma limit_cone_lift_map_map_add {D : cone G} (a b : D.X) :
  limit_cone_lift_map G D (a + b) = limit_cone_lift_map G D a + limit_cone_lift_map G D b :=
begin
  apply quotient.sound',
  refine ⟨_, le_sup_left, le_sup_right, _⟩,
  dsimp,
  ext j,
  dsimp [limit_cone_lift_map],
  simp only [cone_point_type_filt.trans_apply, cone_point_type.coe_incl_preimage_apply,
    cone_point_type_filt.add'_apply_coe, coe_cast_le, coe_cast_le'],
  exact (D.π.app j).map_add a b,
end

lemma limit_cone_lift_map_strict {D : cone G} {x : D.X} (c : ℝ≥0) (hx : x ∈ filtration D.X c) :
  limit_cone_lift_map G D x ∈ filtration (cone_point_type G) c :=
begin
  dsimp [limit_cone_lift_map],
  change _ ∈ set.range _,
  refine ⟨⟨λ j, (D.π.app j).level ⟨x,hx⟩, _⟩, _⟩,
  { intros i j e,
    ext,
    dsimp,
    simp },
  { dsimp,
    apply quotient.sound',
    refine ⟨_, le_sup_left, le_sup_right, _⟩,
    dsimp,
    ext j,
    simpa }
end

def limit_cone_lift (D : cone G) : D.X ⟶ cone_point G :=
{ to_fun := limit_cone_lift_map _ D,
  map_zero' := limit_cone_lift_map_map_zero _,
  map_add' := limit_cone_lift_map_map_add _,
  strict' := λ c x hx, limit_cone_lift_map_strict G c hx,
  continuous' := begin
    intros c,
    rw (cone_point_type.filt_homeo G c).inducing.continuous_iff,
    let E : filtration D.X c → cone_point_type_filt G c := λ t,
      ⟨λ j, (D.π.app j).level t, _⟩,
    swap, {
      intros i j e,
      ext,
      dsimp,
      simp },
    have : (cone_point_type.filt_homeo G c) ∘ pseudo_normed_group.level
      (limit_cone_lift_map G D) (λ c x hx, limit_cone_lift_map_strict G c hx) c = E,
    { ext1,
      apply_fun (cone_point_type.filt_homeo G c).symm,
      dsimp [E],
      simp only [homeomorph.symm_apply_apply],
      ext,
      apply quotient.sound',
      refine ⟨_, le_sup_left, le_sup_right, _⟩,
      ext,
      dsimp,
      simp only [cone_point_type_filt.trans_apply, coe_cast_le, coe_cast_le'],
      refl },
    rw this,
    apply continuous.subtype_mk,
    apply continuous_pi,
    intros j,
    dsimp,
    apply (D.π.app j).level_continuous,
  end }

def limit_cone_is_limit : is_limit (limit_cone G) :=
{ lift := λ S, limit_cone_lift _ _,
  fac' := begin
    intros S j,
    ext,
    change (limit_cone G).π.app j _ = _,
    dsimp [limit_cone_lift, limit_cone, limit_cone_lift_map, proj],
    simpa,
  end,
  uniq' := begin
    intros S m h,
    ext,
    dsimp [limit_cone_lift, limit_cone_lift_map],
    rw ← (m x).preimage_spec,
    apply quotient.sound',
    refine ⟨_, le_sup_left, le_sup_right, _⟩,
    ext j,
    dsimp,
    simp only [cone_point_type_filt.trans_apply, coe_cast_le, coe_cast_le'],
    specialize h j,
    apply_fun (λ e, e x) at h,
    exact h,
  end }

-- This is the goal of this section...
instance : has_limit G := has_limit.mk ⟨limit_cone _, limit_cone_is_limit _⟩

instance : has_limits CompHausFiltPseuNormGrp₁ :=
⟨λ J hJ, { has_limit := λ G, by resetI; apply_instance }⟩

instance (c : ℝ≥0) : preserves_limit G (level.obj c) :=
preserves_limit_of_preserves_limit_cone (limit_cone_is_limit _)
{ lift := λ S,
    (CompHaus.limit_cone_is_limit.{_ u} ((cone_point_diagram G).obj (as_small.up.obj c))).lift
    _ ≫ (cone_point_type.filt_iso _ _).inv,
  fac' := begin
    intros S j,
    dsimp,
    rw category.assoc,
    convert (CompHaus.limit_cone_is_limit.{_ u}
      ((cone_point_diagram G).obj (as_small.up.obj c))).fac S j,
    ext ⟨t,ht⟩,
    dsimp [limit_cone, cone_point_type.filt_iso, cone_point_type.filt_homeo,
      homeomorph.homeomorph_of_continuous_open, cone_point_type.filt_equiv,
      level, proj, CompHaus.limit_cone, Top.limit_cone],
    simpa,
  end,
  uniq' := begin
    intros S m hm,
    rw iso.eq_comp_inv,
    apply (CompHaus.limit_cone_is_limit.{_ u} ((cone_point_diagram G).obj (as_small.up.obj c))).uniq,
    intros j,
    rw [← hm, category.assoc],
    congr' 1,
    rw ← iso.eq_inv_comp,
    ext ⟨t,ht⟩,
    dsimp [limit_cone, cone_point_type.filt_iso, cone_point_type.filt_homeo,
      homeomorph.homeomorph_of_continuous_open, cone_point_type.filt_equiv,
      level, proj, CompHaus.limit_cone, Top.limit_cone],
    simpa,
  end } .

instance (c : ℝ≥0) : preserves_limits (level.obj c) :=
{ preserves_limits_of_shape := λ J _, by exactI
  { preserves_limit := λ G, by apply_instance, } }

lemma mem_filtration_iff_of_is_limit (C : cone G) (hC : is_limit C) (c : ℝ≥0) (x : C.X) :
  x ∈ pseudo_normed_group.filtration C.X c ↔
  (∀ j : J, C.π.app j x ∈ pseudo_normed_group.filtration (G.obj j) c) :=
begin
  split,
  { intros h j,
    apply (C.π.app j).strict h },
  { intro h,
    let E := limit_cone G,
    let e : C ≅ E := hC.unique_up_to_iso (limit_cone_is_limit _),
    let eX : C.X ≅ E.X := (cones.forget _).map_iso e,
    let w := eX.hom x,
    have hw : ∀ j, E.π.app j w ∈ filtration (G.obj j) c,
    { intros j,
      dsimp only [w],
      change (eX.hom ≫ E.π.app _) _ ∈ _,
      dsimp only [eX, functor.map_iso, cones.forget],
      convert h j,
      simp },
    suffices : w ∈ filtration (limit_cone G).X c,
    { convert eX.inv.strict this,
      change _ = (eX.hom ≫ eX.inv) x,
      rw iso.hom_inv_id,
      refl },
    change ∃ z, _,
    refine ⟨⟨λ j, ⟨_, hw _⟩, _⟩, _⟩,
    { intros i j f,
      ext1,
      dsimp,
      change (E.π.app i ≫ G.map f) _ = _,
      rw E.w },
    { obtain ⟨i,z,hz⟩ := cone_point_type.incl_jointly_surjective w,
      let d : ℝ≥0 := i ⊔ c,
      conv_rhs { rw ← hz },
      rw ← cone_point_type.incl_trans (le_sup_left : i ≤ d),
      rw ← cone_point_type.incl_trans (le_sup_right : c ≤ d),
      congr' 1,
      dsimp [cone_point_type_filt.trans],
      ext j,
      dsimp,
      change E.π.app j _ = _,
      rw ← hz,
      dsimp [E, limit_cone, proj],
      simp } }
end

lemma is_limit_ext (C : cone G) (hC : is_limit C) (x y : C.X)
  (h : ∀ j, C.π.app j x = C.π.app j y) : x = y :=
begin
  let E := limit_cone G,
  let e : C ≅ E := hC.unique_up_to_iso (limit_cone_is_limit _),
  let eX : C.X ≅ E.X := (cones.forget _).map_iso e,
  apply_fun eX.hom,
  swap,
  { intros a b hh,
    apply_fun (λ e, eX.inv e) at hh,
    change (eX.hom ≫ eX.inv) _ = (eX.hom ≫ eX.inv) _ at hh,
    simpa only [iso.hom_inv_id] using hh },
  have hh : ∀ j, (E.π.app j) (eX.hom x) = (E.π.app j) (eX.hom y),
  { intros j,
    change (eX.hom ≫ E.π.app j) x = (eX.hom ≫ E.π.app j) y,
    convert h j using 2,
    all_goals { simp } },
  obtain ⟨ca,a,ha⟩ := cone_point_type.incl_jointly_surjective (eX.hom x),
  obtain ⟨cb,b,hb⟩ := cone_point_type.incl_jointly_surjective (eX.hom y),
  rw [← ha, ← hb] at ⊢ hh,
  let d : ℝ≥0 := ca ⊔ cb,
  rw ← cone_point_type.incl_trans (le_sup_left : ca ≤ d) at ⊢ hh,
  rw ← cone_point_type.incl_trans (le_sup_right : cb ≤ d) at ⊢ hh,
  congr' 1,
  ext j,
  specialize hh j,
  convert hh using 1,
  all_goals { dsimp [E, limit_cone, proj],
    simp },
end

end limits

section products

/-!
In this section, we construct explicit finite products.
-/

def product {α : Type u} [fintype α] (X : α → CompHausFiltPseuNormGrp₁.{u}) :
  CompHausFiltPseuNormGrp₁.{u} :=
{ M := Π i, X i,
  exhaustive' := begin
    intro m,
    choose cs hcs using (λ i, (X i).exhaustive (m i)),
    have : ∃ c : ℝ≥0, ∀ i, cs i ≤ c,
    { use finset.univ.sup cs,
      intros i,
      apply finset.le_sup (finset.mem_univ i) },
    obtain ⟨c,hc⟩ := this,
    refine ⟨c, λ i, pseudo_normed_group.filtration_mono (hc i) (hcs i)⟩,
  end }

@[simps]
def product.π {α : Type u} [fintype α] (X : α → CompHausFiltPseuNormGrp₁.{u}) (i : α) :
  product X ⟶ X i :=
{ to_fun := λ m, m i,
  map_zero' := rfl,
  map_add' := λ x y, rfl,
  strict' := λ c x hx, hx i,
  continuous' := begin
    -- This can be golfed.
    intros c,
    have h : inducing (pseudo_normed_group.filtration_pi_equiv (λ i, X i) c) := ⟨rfl⟩,
    let e : ↥(pseudo_normed_group.filtration ↥(product X) c) →
      ↥(pseudo_normed_group.filtration ↥(X i) c) :=
      pseudo_normed_group.level (λ (m : ↥(product X)), m i) _ c,
    swap,
    { intros c x hx,
      apply hx },
    change continuous e,
    have : e = _ ∘ (pseudo_normed_group.filtration_pi_equiv (λ i, X i) c),
    rotate 2,
    { intros x, exact x i },
    { ext, refl },
    erw [this],
    apply continuous.comp,
    apply continuous_apply,
    refine inducing.continuous h
  end }

@[simps]
def product.lift {α : Type u} [fintype α] (X : α → CompHausFiltPseuNormGrp₁.{u})
  (M : CompHausFiltPseuNormGrp₁.{u}) (f : Π i, M ⟶ X i) :
  M ⟶ product X :=
{ to_fun := λ m i, f _ m,
  map_zero' := by { ext, simp },
  map_add' := by { intros, ext, simp },
  strict' := λ c x hx i, (f i).strict hx,
  continuous' := begin
    intros c,
    have h : inducing (pseudo_normed_group.filtration_pi_equiv (λ i, X i) c) := ⟨rfl⟩,
    rw [h.continuous_iff, continuous_pi_iff],
    intros i,
    exact (f i).continuous' c,
  end }

@[simp, reassoc]
lemma product.lift_π {α : Type u} [fintype α] (X : α → CompHausFiltPseuNormGrp₁.{u})
  (M : CompHausFiltPseuNormGrp₁.{u}) (f : Π i, M ⟶ X i) (i) :
  product.lift X M f ≫ product.π X i = f i := by { ext, simp }

lemma product.lift_unique {α : Type u} [fintype α] (X : α → CompHausFiltPseuNormGrp₁.{u})
  (M : CompHausFiltPseuNormGrp₁.{u}) (f : Π i, M ⟶ X i) (g : M ⟶ product X)
  (hg : ∀ i, g ≫ product.π X i = f i) : g = product.lift X M f :=
by { ext, simp [← hg] }

lemma product.hom_ext {α : Type u} [fintype α] (X : α → CompHausFiltPseuNormGrp₁.{u})
  (M : CompHausFiltPseuNormGrp₁.{u}) (g₁ g₂ : M ⟶ product X)
  (h : ∀ i, g₁ ≫ product.π X i = g₂ ≫ product.π X i) : g₁ = g₂ :=
begin
  rw [product.lift_unique X M _ g₁ (λ i, rfl), product.lift_unique X M _ g₂ (λ i, rfl)],
  simp [h],
end

end products

end CompHausFiltPseuNormGrp₁


example (f : Fin n → Prop) (h : ∀ i h, i = 0 → f ⟨i, h⟩) : f i := by
  apply h
  rw [show i.1 = 0 from sorry]

def foo (x : Fin n) : Nat :=
  match x with
  | ⟨i, _⟩ => 5 + i

example (x : Fin n) : foo x = 5 := by
  simp [foo]
  rw [show x.1 = 0 from sorry]


import free_pfpng.setup
import for_mathlib.logic

noncomputable theory

open_locale classical big_operators

open category_theory
open opposite

universe u

instance Condensed_Ab_to_CondensedSet_faithful :
  faithful Condensed_Ab_to_CondensedSet :=
{ map_injective' := begin
    intros X Y f g h, ext W t : 4,
    apply_fun (λ e, e.val.app W t) at h, dsimp at h,
    exact h
  end }

lemma category_theory.epi_to_colimit_of_exists {J : Type u}
  [small_category J] {C : Type*} [category.{u} C]
  {F : J ⥤ C} (T : C)
  (E : limits.cocone F) (hE : limits.is_colimit E)
  (f : T ⟶ E.X)
  (h : ∀ j : J,
    ∃ (Z : C) (p : Z ⟶ T) (q : Z ⟶ F.obj j) (hq : epi q),
      q ≫ E.ι.app j = p ≫ f) : epi f :=
begin
  constructor, intros W a b hh,
  apply hE.hom_ext, intros j, specialize h j,
  obtain ⟨Z,p,q,hq,w⟩ := h, resetI,
  rw ← cancel_epi q, simp_rw [← category.assoc, w,
    category.assoc, hh],
end

lemma epi_Profinite_to_Condensed_map_of_epi {X Y : Profinite.{u}}
  (f : X ⟶ Y) [hf : epi f] : epi (Profinite_to_Condensed.map f) :=
begin
  constructor, intros Z a b h, ext W q : 34, induction W using opposite.rec,
  have hZ := Z.2,
  rw is_sheaf_iff_is_sheaf_of_type at hZ,
  rw Z.val.is_proetale_sheaf_of_types_tfae.out 0 1 at hZ,
  let q' := q.down,
  dsimp at q q',
  dsimp [functor.is_proetale_sheaf_of_types] at hZ,
  specialize hZ punit W (λ _, Profinite.pullback f q')
    (λ _, Profinite.pullback.snd _ _) _ _,
  { intro w,
    rw Profinite.epi_iff_surjective at hf,
    obtain ⟨x, hx⟩ := hf (q' w),
    refine ⟨punit.star, ⟨(x, w), hx⟩, rfl⟩, },
  { intros i, dsimp, refine Z.val.map _ (b.val.app (op W) q),
    refine quiver.hom.op _, exact Profinite.pullback.snd _ _ },
  specialize hZ _,
  { clear hZ,
    rintro ⟨⟩ ⟨⟩ S g₁ g₂ H, dsimp only at H,
    apply_fun (λ φ, Z.val.map φ.op (b.val.app (op W) q)) at H,
    simp only [op_comp, Z.val.map_comp] at H, exact H, },
  obtain ⟨t,ht1,ht2⟩ := hZ,
  have : b.val.app (op W) q = t,
  { apply ht2,
    intros i, refl },
  rw this, apply ht2,
  intros i, dsimp,
  change (a.val.app (op W) ≫ Z.val.map _) q =
    (b.val.app (op W) ≫ Z.val.map _) q,
  simp only [← nat_trans.naturality],
  dsimp,
  apply_fun (λ e, Profinite_to_Condensed.map (Profinite.pullback.fst f q') ≫ e) at h,
  apply_fun (λ e, e.val.app (op (Profinite.pullback f q'))) at h,
  dsimp at h,
  let i : (Profinite.pullback f q').to_Condensed.val.obj (op (Profinite.pullback f q')) :=
    ulift.up (𝟙 _),
  apply_fun (λ e, e i) at h,
  dsimp [ulift_functor] at h,
  convert h,
  all_goals
  { ext1,
    dsimp [Profinite.to_Condensed],
    simp only [category.id_comp, Profinite.pullback.condition] },
end

/-
inductive pmz : set ℤ
| neg_one : pmz (-1)
| zero : pmz 0
| one : pmz 1

def pmz_eq : pmz = {0,1,-1} :=
begin
  ext, split,
  { intros h, cases h, right, right, simpa, left, simp, right, left, simp },
  { intros h, simp at h, rcases h with (rfl|rfl|rfl),
    apply pmz.zero,
    apply pmz.one,
    apply pmz.neg_one }
end

lemma pmz_finite : set.finite pmz :=
by simp [pmz_eq]

instance fintype_pmz : fintype pmz := pmz_finite.fintype
-/

--abbreviation Profinite.pow (S : Profinite.{u}) (n : ℕ) : Profinite.{u} :=
--Profinite.product (λ i : fin n, S)

/-- `S.pmz n` is `(S × {-1,0,1})^n`. -/
def Profinite.pmz (S : Profinite.{u}) (n : ℕ) : Profinite.{u} :=
Profinite.sigma $ λ (x : ulift.{u} (fin n → sign_type)), S.pow n

/-- the canonical map of condensed sets `(S × {-1,0,1})^n ⟶ ℤ[S]` -/
def Profinite.pmz_to_free' (S : Profinite.{u}) (n : ℕ) :
  (S.pmz n).to_Condensed ⟶ Condensed_Ab_to_CondensedSet.obj S.free' :=
(Profinite.to_Condensed_equiv (S.pmz n) (Condensed_Ab_to_CondensedSet.obj S.free')).symm $
  (CondensedSet.val_obj_sigma_equiv (λ (f : ulift.{u} (fin n → sign_type)), S.pow n)
    (Condensed_Ab_to_CondensedSet.obj S.free')).symm $
λ (f : ulift.{u} (fin n → sign_type)),
let e := proetale_topology.to_sheafify (S.to_Condensed.val ⋙ AddCommGroup.free') in
e.app (op $ S.pow n) $
  ∑ i : fin n, finsupp.single (ulift.up $ Profinite.product.π _ i) (f.down i : ℤ)

def Profinite.pmz_functor (n : ℕ) : Profinite.{u} ⥤ Profinite.{u} :=
{ obj := λ S, S.pmz n,
  map := λ S T f,
    Profinite.sigma.desc _ $ λ e,
      (Profinite.product.lift (λ i : fin n, T)
        (λ i, Profinite.product.π _ i ≫ f)) ≫ Profinite.sigma.ι _ e,
  map_id' := begin
    intros X,
    apply Profinite.sigma.hom_ext, intros e,
    erw category.comp_id, refl,
  end,
  map_comp' := begin
    intros X Y Z f g,
    apply Profinite.sigma.hom_ext, intros e, dsimp, simp,
    erw [Profinite.sigma.ι_desc],
    refl,
  end }

def Profinite.pmz_diagram (S : Profinite.{u}) (n : ℕ) :
  discrete_quotient S ⥤ Profinite.{u} :=
S.diagram ⋙ Profinite.pmz_functor n

def Profinite.pmz_cone (S : Profinite.{u}) (n : ℕ) : limits.cone (S.pmz_diagram n) :=
(Profinite.pmz_functor n).map_cone S.as_limit_cone

def Profinite.sigma_functor {J : Type u} [small_category J]
  (F : J ⥤ Profinite.{u}) (α : Type u) [fintype α] :
  J ⥤ Profinite.{u} :=
{ obj := λ j, Profinite.sigma (λ a : α, F.obj j),
  map := λ i j e, Profinite.sigma.desc _ $ λ a,
    F.map e ≫ Profinite.sigma.ι _ a,
  map_id' := begin
    intros j, apply Profinite.sigma.hom_ext, intros a,
    simp,
  end,
  map_comp' := begin
    intros i j k e f,
    apply Profinite.sigma.hom_ext, intros a,
    simp,
  end }

def Profinite.sigma_cone {J : Type u} [small_category J]
  {F : J ⥤ Profinite.{u}} (α : Type u) [fintype α]
  (E : limits.cone F) :
  limits.cone (Profinite.sigma_functor F α) :=
{ X := Profinite.sigma (λ a : α, E.X),
  π :=
  { app := λ j, Profinite.sigma.desc _ $ λ a,
      E.π.app j ≫ Profinite.sigma.ι _ a,
    naturality' := begin
      intros i j e, dsimp,
      apply Profinite.sigma.hom_ext, intros a,
      simp, dsimp [Profinite.sigma_functor], simp,
    end } }

def Profinite.sigma_to_limit {J : Type u} [small_category J]
  (F : J ⥤ Profinite.{u}) (α : Type u) [fintype α]
  (E : limits.cone F) :
  (Profinite.sigma_cone α E).X ⟶
    (Profinite.limit_cone (Profinite.sigma_functor F α)).X :=
Profinite.sigma.desc _ $ λ a, (Profinite.limit_cone_is_limit
  (Profinite.sigma_functor F α)).lift ⟨E.X,
  { app := λ j, E.π.app j ≫ Profinite.sigma.ι _ a,
  naturality' := begin
    intros i j e, dsimp [Profinite.sigma_functor],
    simp,
  end }⟩

lemma Profinite.exists_of_sigma_limit {J : Type u} [small_category J]
  (F : J ⥤ Profinite.{u}) (α : Type u) [fintype α] [is_cofiltered J]
  (t : (Profinite.limit_cone (Profinite.sigma_functor F α)).X) :
  ∃ (a₀ : α) (t₀ : (Profinite.limit_cone F).X),
    ∀ j : J, Profinite.sigma.ι _ a₀
      ((Profinite.limit_cone F).π.app j t₀) =
      (Profinite.limit_cone (Profinite.sigma_functor F α)).π.app j t :=
begin
  rcases t with ⟨t,ht⟩, dsimp at ht,
  obtain ⟨j₀⟩ : nonempty J := is_cofiltered.nonempty,
  let a₀ := (t j₀).1, use a₀,
  have h1 : ∀ ⦃i j : J⦄ (f : i ⟶ j), (t i).1 = (t j).1,
  { intros i j e, specialize ht e,
    apply_fun (λ q, q.1) at ht,
    cases t i, exact ht },
  have h2 : ∀ j : J, (t j).1 = a₀,
  { intros j,
    let j₁ := is_cofiltered.min j j₀,
    rw ← h1 (is_cofiltered.min_to_left j j₀), dsimp [a₀],
    rw ← h1 (is_cofiltered.min_to_right j j₀) },
  let t₀ : (Profinite.limit_cone F).X := ⟨_,_⟩,
  rotate,
  { intros j, exact (t j).2 },
  { intros i j e,
    specialize ht e,
    cases (t i),
    dsimp [Profinite.sigma_functor, Profinite.sigma.desc, Profinite.sigma.ι] at ht,
    cases t j,
    erw sigma.mk.inj_iff at ht,
    exact eq_of_heq ht.2 },
  use t₀,
  intros j,
  dsimp [Profinite.limit_cone, Profinite.sigma_functor, Profinite.sigma.ι,
    Profinite.sigma.desc, CompHaus.limit_cone, Top.limit_cone], ext,
  exact (h2 _).symm, refl,
end

lemma Profinite.bijective_sigma_to_limit {J : Type u} [small_category J]
  (F : J ⥤ Profinite.{u}) (α : Type u) [fintype α]
  (E : limits.cone F) (hE : limits.is_limit E) [is_cofiltered J] :
  function.bijective (Profinite.sigma_to_limit F α E) :=
begin
  split,
  { rintros ⟨a,x⟩ ⟨b,y⟩ h,
    dsimp [Profinite.sigma_to_limit, Profinite.sigma.desc,
      Profinite.limit_cone_is_limit, CompHaus.limit_cone_is_limit,
      Top.limit_cone_is_limit] at h,
    apply_fun (λ e, e.1) at h,
    have hh := h,
    obtain ⟨j₀⟩ : nonempty J := is_cofiltered.nonempty,
    apply_fun (λ e, (e j₀).1) at h, dsimp [Profinite.sigma.ι] at h,
    subst h, ext, refl,
    apply heq_of_eq,
    apply limits.concrete.is_limit_ext _ hE,
    intros jj, apply_fun (λ e, e jj) at hh,
    erw sigma.mk.inj_iff at hh,
    exact eq_of_heq hh.2 },
  { rintros t,
    obtain ⟨a,s,ht⟩ := Profinite.exists_of_sigma_limit F α t,
    use a, let EE : E.X ≅ (Profinite.limit_cone F).X :=
      hE.cone_point_unique_up_to_iso (Profinite.limit_cone_is_limit _),
    use EE.inv s, dsimp, ext j : 2,
    convert ht j, ext, refl,
    apply heq_of_eq,
    change ((hE.lift (Profinite.limit_cone F)) ≫ E.π.app j) s = _,
    rw hE.fac, refl }
end

lemma Profinite.is_iso_lift_sigma_cone {J : Type u} [small_category J]
  {F : J ⥤ Profinite.{u}} (α : Type u) [fintype α] [is_cofiltered J]
  (E : limits.cone F) (hE : limits.is_limit E) :
  is_iso ((Profinite.limit_cone_is_limit _).lift (Profinite.sigma_cone α E)) :=
begin
  apply Profinite.is_iso_of_bijective,
  convert Profinite.bijective_sigma_to_limit F α E hE,
  symmetry,
  apply (Profinite.limit_cone_is_limit (Profinite.sigma_functor F α)).uniq,
  intros j,
  apply Profinite.sigma.hom_ext,
  intros a, refl,
end

def Profinite.sigma_cone_is_limit {J : Type u} [small_category J]
  {F : J ⥤ Profinite.{u}} (α : Type u) [fintype α] [is_cofiltered J]
  (E : limits.cone F) (hE : limits.is_limit E) :
  limits.is_limit (Profinite.sigma_cone α E) :=
begin
  haveI : is_iso ((Profinite.limit_cone_is_limit _).lift (Profinite.sigma_cone α E)) :=
    Profinite.is_iso_lift_sigma_cone α E hE,
  apply limits.is_limit.of_point_iso (Profinite.limit_cone_is_limit _),
  assumption
end

def Profinite.pmz_to_limit (S : Profinite.{u}) (n : ℕ) :
  S.pmz n ⟶ (Profinite.limit_cone (S.pmz_diagram n)).X :=
Profinite.sigma.desc _ $ λ f,
  (Profinite.limit_cone_is_limit (S.pmz_diagram n)).lift ⟨S.pow n,
  { app := λ T, Profinite.map_pow (S.as_limit_cone.π.app T) n ≫
      Profinite.sigma.ι _ f,
    naturality' := begin
      intros A B e,
      dsimp [Profinite.pmz_diagram, Profinite.pmz_functor],
      simpa,
    end }⟩

def Profinite.pow_functor (n : ℕ) : Profinite.{u} ⥤ Profinite.{u} :=
{ obj := λ S, S.pow n,
  map := λ S T f, Profinite.map_pow f n,
  map_id' := begin
    intros X, apply Profinite.product.hom_ext, intros i, dsimp [Profinite.map_pow], simp,
  end,
  map_comp' := begin
    intros X Y Z f g,
    apply Profinite.product.hom_ext, intros i, dsimp [Profinite.map_pow], simp,
  end }

def Profinite.pow_cone {J : Type u} [small_category J] {F : J ⥤ Profinite.{u}}
  (E : limits.cone F) (n : ℕ) : limits.cone (F ⋙ Profinite.pow_functor n) :=
(Profinite.pow_functor n).map_cone E

def Profinite.pow_cone_is_limit
  {J : Type u} [small_category J] {F : J ⥤ Profinite.{u}}
  (E : limits.cone F) (hE : limits.is_limit E) (n : ℕ) :
  limits.is_limit (Profinite.pow_cone E n) :=
{ lift := λ Q, Profinite.product.lift _ $ λ a,
    hE.lift ⟨Q.X,
    { app := λ j, Q.π.app j ≫ Profinite.product.π _ a,
      naturality' := begin
        intros i j e, dsimp,
        simp only [category.id_comp, category.assoc],
        rw ← Q.w e,
        dsimp [Profinite.pow_functor, Profinite.map_pow],
        simp,
      end }⟩,
  fac' := begin
    intros Q j, apply Profinite.product.hom_ext, intros i,
    dsimp [Profinite.pow_cone, Profinite.pow_functor, Profinite.map_pow],
    simp only [category.assoc, Profinite.product.lift_π, Profinite.product.lift_π_assoc,
      limits.is_limit.fac],
  end,
  uniq' := begin
    intros Q m hm,
    apply Profinite.product.hom_ext, intros a,
    dsimp [Profinite.pow_cone, Profinite.pow_functor, Profinite.map_pow],
    simp only [Profinite.product.lift_π],
    apply hE.hom_ext,
    intros j,
    simp only [category.assoc, limits.is_limit.fac], rw ← hm,
    dsimp [Profinite.pow_cone, Profinite.pow_functor, Profinite.map_pow],
    simp only [category.assoc, Profinite.product.lift_π],
  end }

lemma Profinite.is_iso_pmz_to_limit (S : Profinite.{u}) (n : ℕ) :
  is_iso (S.pmz_to_limit n) :=
begin
  let E := Profinite.sigma_cone (ulift.{u} (fin n → sign_type))
    (Profinite.pow_cone S.as_limit_cone n),
  let hE : limits.is_limit E := Profinite.sigma_cone_is_limit _ _
    (Profinite.pow_cone_is_limit _ S.as_limit n),
  let q : E.X ≅ (Profinite.limit_cone (S.pmz_diagram n)).X :=
    hE.cone_point_unique_up_to_iso (Profinite.limit_cone_is_limit _),
  have : is_iso q.hom := infer_instance,
  convert this,
  apply Profinite.sigma.hom_ext, intros e,
  apply (Profinite.limit_cone_is_limit _).hom_ext,
  intros T,
  refl,
end

def Profinite.pmz_cone_is_limit (S : Profinite.{u}) (n : ℕ) :
  limits.is_limit (S.pmz_cone n) :=
begin
  apply limits.is_limit.of_point_iso (Profinite.limit_cone_is_limit _),
  convert Profinite.is_iso_pmz_to_limit S n,
  apply Profinite.sigma.hom_ext, intros a,
  apply (Profinite.limit_cone_is_limit _).hom_ext, intros j,
  refl,
end

-- A finite product of finite discrete sets is discrete.
instance Profinite.discrete_topology_pow
  (S : Profinite.{u}) [discrete_topology S] (n : ℕ) :
  discrete_topology (S.pow n) :=
Pi.discrete_topology

-- A finite union of finite products of finite discrete sets is discrete.
instance Profinite.discrete_topology_pmz
  (S : Profinite.{u}) [discrete_topology S] (n : ℕ) :
  discrete_topology (S.pmz n) :=
sigma.discrete_topology

-- move this
lemma _root_.sign_type.nnnorm_coe_int_le_one : ∀ i : sign_type, ∥(i : ℤ)∥₊ ≤ 1
| sign_type.zero := by { erw [nnnorm_zero], exact zero_le', }
| sign_type.neg := by { erw [nnnorm_neg], norm_num, }
| sign_type.pos := by { erw [nnnorm_one], }

def Profinite.pmz_to_level_component (S : Profinite.{u}) (j : nnreal) (T : discrete_quotient S)
  (e : fin ⌊j⌋₊ → sign_type) :
  (Profinite.of ↥T).pow ⌊j⌋₊ ⟶
  (ProFiltPseuNormGrp₁.level.obj j).obj (free_pfpng_functor.obj (Fintype.of ↥T)) :=
{ to_fun := λ t,
  { val := ∑ i : fin ⌊j⌋₊, (λ s, if t i = s then (e i : ℤ) else 0),
    property := begin
      have : ∑ i : fin ⌊j⌋₊, (∑ s : T, if t i = s then (1 : nnreal) else 0) ≤ j,
      { calc _
            ≤ ∑ i : fin ⌊j⌋₊, (1 : nnreal) : _
        ... ≤ j : _,
        { apply finset.sum_le_sum, rintro i -, apply le_of_eq,
          erw [finset.sum_eq_single_of_mem (t i : T) (@finset.mem_univ T _ _), if_pos rfl],
          rintro s - hs, rw [if_neg hs.symm], },
        { simp only [finset.sum_const, finset.card_fin, nat.smul_one_eq_coe],
          exact nat.floor_le zero_le' } },
      apply pseudo_normed_group.filtration_mono this,
      apply pseudo_normed_group.sum_mem_filtration,
      rintro i -,
      apply finset.sum_le_sum,
      rintro s -,
      dsimp,
      split_ifs,
      { apply sign_type.nnnorm_coe_int_le_one },
      { rw nnnorm_zero },
    end },
  continuous_to_fun := continuous_of_discrete_topology }

def Profinite.pmz_to_level (S : Profinite.{u}) (j : nnreal) (T : discrete_quotient S) :
  (Profinite.of T).pmz ⌊j⌋₊ ⟶
    (ProFiltPseuNormGrp₁.level.obj j).obj (free_pfpng_functor.obj $ Fintype.of T) :=
Profinite.sigma.desc _ $ λ e, S.pmz_to_level_component j T (ulift.down e)

lemma Profinite.pmz_to_level_nat_trans_aux
  (S : Profinite.{u}) (j : nnreal) (T₁ T₂ : discrete_quotient S) (f : T₁ ⟶ T₂)
  (e : fin ⌊j⌋₊ → sign_type) (t : (Profinite.of T₁).pow ⌊j⌋₊) (s : T₂) :
(∑ i : fin ⌊j⌋₊, λ s : T₂, ite (S.fintype_diagram.map f (t i) = s) (e i : ℤ) 0) s =
  (@finset.filter (@bundled.α fintype (S.fintype_diagram.obj T₁))
     (λ w : T₁, S.fintype_diagram.map f w = s)
     (λ (a : @bundled.α fintype (S.fintype_diagram.obj T₁)),
        classical.prop_decidable _)
     (@finset.univ (@bundled.α fintype (S.fintype_diagram.obj T₁))
        (@Fintype.fintype (S.fintype_diagram.obj T₁)))).sum
    (∑ (i : fin ⌊j⌋₊), λ s : T₁, @ite ℤ (t i = s) _ ↑(e i) 0) :=
begin
  simp only [finset.sum_apply],
  rw finset.sum_comm,
  refine finset.sum_congr rfl _,
  rintro i -,
  rw finset.sum_ite_eq,
  simp only [finset.mem_filter, finset.mem_univ, true_and],
end

def Profinite.pmz_to_level_nat_trans (S : Profinite.{u}) (j : nnreal) :
  S.pmz_diagram ⌊j⌋₊ ⟶ (S.fintype_diagram ⋙ free_pfpng_functor) ⋙
    (ProFiltPseuNormGrp₁.level.obj j) :=
{ app := λ T, S.pmz_to_level j T,
  naturality' := begin
    intros T₁ T₂ f,
    dsimp [Profinite.pmz_diagram, Profinite.pmz_to_level, Profinite.pmz_functor],
    apply Profinite.sigma.hom_ext,
    rintro ⟨e⟩,
    simp only [Profinite.sigma.ι_desc_assoc, category.assoc, Profinite.sigma.ι_desc],
    ext t s,
    exact Profinite.pmz_to_level_nat_trans_aux S j T₁ T₂ f e t s,
  end }

def Profinite.pmz_to_free_pfpng (S : Profinite.{u}) (j : nnreal) :
  S.pmz ⌊j⌋₊ ⟶ (ProFiltPseuNormGrp₁.level.obj j).obj S.free_pfpng :=
let E := limits.is_limit_of_preserves (ProFiltPseuNormGrp₁.level.obj j)
  (limits.limit.is_limit (S.fintype_diagram ⋙ free_pfpng_functor)) in
E.map (S.pmz_cone _) (S.pmz_to_level_nat_trans j)

lemma Profinite.is_limit.surjective_of_surjective
  {J : Type u} [small_category J] (F G : J ⥤ Profinite.{u})
  (α : F ⟶ G) (cF : limits.cone F)
  (cG : limits.cone G) (hcF : limits.is_limit cF) (hcG : limits.is_limit cG)
  [is_cofiltered J] (surj : ∀ (j : J), function.surjective ⇑(α.app j)) :
  function.surjective ⇑(limits.is_limit.map cF hcG α) :=
begin
  have := CompHaus.is_limit.surjective_of_surjective
    (F ⋙ Profinite_to_CompHaus)
    (G ⋙ Profinite_to_CompHaus)
    (whisker_right α _)
    (Profinite_to_CompHaus.map_cone cF)
    (Profinite_to_CompHaus.map_cone cG)
    (limits.is_limit_of_preserves _ hcF)
    (limits.is_limit_of_preserves _ hcG)
    surj,
  change function.surjective
    (Profinite_to_CompHaus.map (limits.is_limit.map cF hcG α)),
  convert this,
  apply hcG.hom_ext, intros j,
  simp only [limits.is_limit.map_π, iso.trans_hom, iso.symm_hom,
    functor.map_iso_hom, limits.is_limit.unique_up_to_iso_hom,
    limits.cone.category_comp_hom, limits.is_limit.lift_cone_morphism_hom,
    limits.limit.is_limit_lift, limits.cones.functoriality_map_hom,
    Profinite_to_CompHaus_map],
  erw [category.assoc, category.assoc],
  erw hcG.fac,
  have := (lifted_limit_maps_to_original
    (limits.limit.is_limit (G ⋙ Profinite_to_CompHaus))).inv.w j,
  erw this,
  dsimp, simp only [limits.limit.lift_π, limits.cones.postcompose_obj_π,
    nat_trans.comp_app, functor.map_cone_π_app,
    Profinite_to_CompHaus_map, whisker_right_app],
  refl,
end

section
variables {α : Type*} [decidable_eq α] [nonempty α]

open finset

-- TODO: Inlining this yields an app-builder exception
lemma exists_signed_sum_aux {n : ℕ} (sgn : ℕ → sign_type) (b : α) [decidable_eq α]
  {f : α → ℤ}
  ⦃a : α⦄ (g : ℕ → α) (i : ℕ) :
  ite ((range (n - (f a).nat_abs)).piecewise g (λ _, a) i = b)
        ((range (n - (f a).nat_abs)).piecewise sgn (λ _, sign (f a)) i : ℤ) 0 =
    (range (n - (f a).nat_abs)).piecewise (λ j, ite (g j = b) ↑(sgn j) 0)
        (λ j, ite (a = b) ↑(sign (f a)) 0) i :=
by { unfold piecewise, split_ifs; refl }

lemma exists_signed_sum (s : finset α) (n : ℕ) (f : α → ℤ) (hn : ∑ i in s, (f i).nat_abs ≤ n) :
  ∃ (sgn : ℕ → sign_type) (g : ℕ → α), (∀ i, g i ∉ s → sgn i = 0) ∧
    ∀ a ∈ s, (∑ i in range n, if g i = a then (sgn i : ℤ) else 0) = f a :=
begin
  induction s using finset.cons_induction with a s ha ih generalizing n,
  { exact ⟨0, classical.arbitrary _, λ _ _, rfl, λ _, false.elim⟩ },
  rw sum_cons at hn,
  obtain ⟨sgn, g, hg, hf⟩ := ih _ (le_tsub_of_add_le_left hn),
  refine ⟨(range $ n - (f a).nat_abs).piecewise sgn (λ _, sign (f a)),
    (range $ n - (f a).nat_abs).piecewise g (λ _, a), λ i hi, _, λ b hb, _⟩,
  { by_cases i ∈ range (n - (f a).nat_abs),
    { rw piecewise_eq_of_mem _ _ _ h at ⊢ hi,
      exact hg _ (λ h, hi $ subset_cons _ h) },
    { rw piecewise_eq_of_not_mem _ _ _ h at hi,
      exact (hi $ mem_cons_self _ _).elim } },
  transitivity ∑ i in range n, (range $ n - (f a).nat_abs).piecewise
    (λ j, ite (g j = b) (sgn j : ℤ) 0) (λ j, ite (a = b) (sign $ f a) 0) i,
  { exact sum_congr rfl (λ i _, exists_signed_sum_aux _ _ _ _) },
  rw [sum_piecewise, (inter_eq_right_iff_subset _ _).2 (range_mono tsub_le_self)],
  rw mem_cons at hb,
  obtain rfl | hb := hb,
  { rw [sum_eq_zero, zero_add, sum_const, if_pos rfl, card_sdiff (range_mono tsub_le_self),
      card_range, card_range, tsub_tsub_cancel_of_le
        (nat.le_of_add_le_left hn), nsmul_eq_mul, mul_comm,
      ←int.sign_eq_sign, int.nat_cast_eq_coe_nat, (f b).sign_mul_nat_abs],
    refine λ i hi, ite_eq_right_iff.2 _,
    rintro rfl,
    rw [hg _ ha, sign_type.coe_zero] },
  { simp_rw [if_neg (ne_of_mem_of_not_mem hb ha).symm, hf _ hb, sum_const_zero, add_zero] }
end

lemma Profinite.pmz_to_free_pfpng_epi_aux' [fintype α]
  (r : nnreal) (f : α → ℤ) (hf : ∑ i : α, ∥f i∥₊ ≤ r) :
  ∃ (sgn : ℕ → sign_type) (g : ℕ → α),
    ∀ t, (∑ i in range ⌊r⌋₊, if g i = t then (sgn i : ℤ) else 0) = f t :=
begin
  refine Exists₂.imp (λ _ _ h t, _) (exists_signed_sum univ ⌊r⌋₊ f _),
  { exact h.2 t (mem_univ _) },
  refine nat.le_floor _,
  simp_rw [nat.cast_sum, nnreal.coe_nat_abs],
  exact hf,
end

lemma Profinite.pmz_to_free_pfpng_epi_aux [fintype α]
  (r : nnreal) (f : α → ℤ) (hf : ∑ i : α, ∥f i∥₊ ≤ r) :
  ∃ (sgn : fin ⌊r⌋₊ → sign_type) (g : fin ⌊r⌋₊ → α),
    (∑ i : fin ⌊r⌋₊, (λ t : α, if g i = t then (sgn i : ℤ) else 0)) = f :=
begin
  obtain ⟨e,g,h⟩ := Profinite.pmz_to_free_pfpng_epi_aux' r f hf,
  let e' : fin ⌊r⌋₊ → sign_type := λ i, e i.1,
  let g' : fin ⌊r⌋₊ → α := λ i, g i.1,
  use [e',g'],
  ext t, rw ← h,
  simp only [finset.sum_apply],
  rw finset.sum_range, refl,
end

end

-- Move this
instance discrete_quotient.nonempty (X : Type*) [topological_space X] [h : nonempty X]
  (T : discrete_quotient X) : nonempty T := ⟨T.proj (nonempty.some h)⟩

instance Profinite.pmz_to_free_pfpng_epi (S : Profinite.{u}) [nonempty S] (j : nnreal) :
  epi (S.pmz_to_free_pfpng j) :=
begin
  rw Profinite.epi_iff_surjective,
  dsimp only [Profinite.pmz_to_free_pfpng],
  have := Profinite.is_limit.surjective_of_surjective _ _ (S.pmz_to_level_nat_trans j)
    (S.pmz_cone _)
    ((ProFiltPseuNormGrp₁.level.obj j).map_cone (limits.limit.cone _))
    (S.pmz_cone_is_limit _)
    (limits.is_limit_of_preserves _ (limits.limit.is_limit _)),
  apply this,
  intros T,
  rintros ⟨(f : T → ℤ), hf : ∑ i : T, _ ≤ _⟩,
  obtain ⟨e,t,ht⟩ := Profinite.pmz_to_free_pfpng_epi_aux j f hf,
  change ∃ a : Σ i, fin ⌊j⌋₊ → T, _,
  use ulift.up e, use t, apply subtype.ext,
  dsimp [Profinite.pmz_to_level_nat_trans, Profinite.pmz_to_level,
    Profinite.sigma.desc, Profinite.pmz_to_level_component],
  exact ht,
end

.

namespace Profinite.epi_free'_to_condensed_setup

variables (S : Profinite.{u}) (j : nnreal)

lemma free'_lift_app_eq (A : Condensed.{u} Ab.{u+1})
  (η : S.to_Condensed ⟶ Condensed_Ab_to_CondensedSet.obj A)
  (T : Profinite.{u}) :
  (proetale_topology.to_sheafify _).app _ ≫ (S.free'_lift η).val.app (op T) =
  free'_lift (η.val.app _) :=
begin
  dsimp [Profinite.free'_lift],
  rw [← nat_trans.comp_app, proetale_topology.to_sheafify_sheafify_lift],
  dsimp [adjunction.whisker_right, free'_lift], simp,
end

lemma free'_lift_app_eq' (A : Condensed.{u} Ab.{u+1})
  (η : S.to_Condensed ⟶ Condensed_Ab_to_CondensedSet.obj A)
  (T : Profinite.{u}) :
  (proetale_topology.to_sheafify _).app _ ≫ (S.free'_lift η).val.app (op T) =
  ((finsupp.lift ↥(A.val.obj (op T)) ℤ
      (((Sheaf_to_presheaf proetale_topology (Type (u+1))).obj S.to_Condensed).obj (op T)))
   (η.val.app (op T))).to_add_monoid_hom :=
begin
  rw free'_lift_app_eq, rw free'_lift_eq_finsupp_lift,
end

instance (A : Condensed.{u} Ab.{u+1}) (T) :
  add_comm_group ((Condensed_Ab_to_CondensedSet.obj A).val.obj T) :=
show add_comm_group (A.val.obj T), by apply_instance

lemma free_pfpng_ext (u v : S.free_pfpng)
  (huv : ∀ T : discrete_quotient S, S.free_pfpng_π T u = S.free_pfpng_π T v) : u = v :=
begin
  let E : limits.cone (S.fintype_diagram ⋙ free_pfpng_functor) :=
    ProFiltPseuNormGrp₁.bounded_cone
    ⟨Ab.explicit_limit_cone.{u u} _, Ab.explicit_limit_cone_is_limit _⟩,
  let hE : limits.is_limit E := ProFiltPseuNormGrp₁.bounded_cone_is_limit _,
  let ee : S.free_pfpng ≅ E.X := (limits.limit.is_limit _).cone_point_unique_up_to_iso hE,
  apply_fun ee.hom, swap,
  { intros x y hh, apply_fun ee.inv at hh, simpa using hh },
  ext T : 3, exact huv T,
end

variables (x : S.pmz ⌊j⌋₊) (T : discrete_quotient S)

lemma lhs_helper : (S.free_pfpng_π T) ((S.pmz_to_free_pfpng j) x).1 =
  ∑ i : fin ⌊j⌋₊, pi.single (T.proj (x.2 i)) (x.1.down i : ℤ) :=
begin
  change (((S.pmz_to_free_pfpng _) ≫ (ProFiltPseuNormGrp₁.level.obj j).map
    (S.free_pfpng_π T)) _).val = _,
  dsimp [Profinite.pmz_to_free_pfpng, Profinite.free_pfpng_π],
  erw ← comp_apply,
  erw limits.is_limit.fac,
  dsimp [Profinite.pmz_to_level_nat_trans, Profinite.pmz_to_level],
  rcases x with ⟨x1,x2⟩,
  dsimp [Profinite.pmz_cone, Profinite.sigma.desc, Profinite.pmz_to_level_component,
    Profinite.pmz_functor, Profinite.product.lift, Profinite.sigma.ι],
  congr' 1, ext i t, erw pi.single_apply,
  split_ifs with h1 h2 h3 h4,
  { refl },
  { exact false.elim (h2 h1.symm) },
  { exact false.elim (h1 h3.symm) },
  { refl }
end

lemma rhs_helper₁ :
  (λ (f : ulift (fin ⌊j⌋₊ → sign_type)),
  ∑ (x : fin ⌊j⌋₊),
    ((proetale_topology.to_sheafify (S.to_Condensed.val ⋙ AddCommGroup.free')).app
      (op (S.pow ⌊j⌋₊)))
      (finsupp.single {down := Profinite.product.π (λ (i : fin ⌊j⌋₊), S) x} ↑(f.down x))) =
  ∑ (x : fin ⌊j⌋₊), (λ f, (proetale_topology.to_sheafify
    (S.to_Condensed.val ⋙ AddCommGroup.free')).app (op (S.pow ⌊j⌋₊)) $
    finsupp.single ⟨Profinite.product.π _ x⟩ (f.down x)) := by { ext, simp }

def _root_.CompHausFiltPseuNormGrp.coe_add_monoid_hom
  (A : CompHausFiltPseuNormGrp.{u}) (T : Profinite.{u}) :
  (CompHausFiltPseuNormGrp.to_Condensed.obj A).val.obj (op T) →+ T → A :=
{ to_fun := λ f, f.down.1,
  map_zero' := rfl,
  map_add' := λ _ _, rfl }

lemma _root_.CompHausFiltPseuNormGrp.to_Condensed_app_sum_apply (n : ℕ)
  (A : CompHausFiltPseuNormGrp.{u}) (T : Profinite.{u})
    (g : fin n → (CompHausFiltPseuNormGrp.to_Condensed.obj A).val.obj (op T)) (t : T) :
  (ulift.down (∑ i : fin n, g i)).1 t = ∑ i : fin n,
    (ulift.down (g i)).1 t :=
begin
  let e := A.coe_add_monoid_hom T,
  change _ = ∑ (i : fin n), (e (g i)) t,
  rw [← finset.sum_apply t finset.univ (λ i : fin n, (e (g i))), ← e.map_sum],
  refl,
end

lemma Profinite.free'_lift_val_obj_sigma_equiv_symm {α : Type u} [fintype α]
  (A : Condensed.{u} Ab.{u+1}) (η : S.to_Condensed ⟶ Condensed_Ab_to_CondensedSet.obj A)
  (X : α → Profinite.{u}) (t) :
  (S.free'_lift η).val.app (op $ Profinite.sigma X)
  ((Condensed.val_obj_sigma_add_equiv _ _ ).symm t) =
  (Condensed.val_obj_sigma_add_equiv _ _ ).symm (λ a, (S.free'_lift η).val.app _ (t a)) :=
begin
  apply_fun Condensed.val_obj_sigma_add_equiv (λ (a : α), X a) A,
  simp only [add_equiv.apply_symm_apply],
  funext a,
  dsimp,
  simp only [← comp_apply, ← nat_trans.naturality],
  simp only [comp_apply],
  congr' 1,
  rw ← Condensed.val_obj_sigma_add_equiv_apply_apply,
  simp only [add_equiv.apply_symm_apply],
end

-- move and rename
def rhs_helper_equiv
  (A : ProFiltPseuNormGrp₁.{u}) :
  A ≃ (CompHausFiltPseuNormGrp.to_Condensed.obj
    (CHFPNG₁_to_CHFPNGₑₗ.obj
      (PFPNG₁_to_CHFPNG₁ₑₗ.obj A))).val.obj
      (op Profinite.punit) :=
{ to_fun := λ a, ulift.up $ ⟨λ _, a, begin
    obtain ⟨c,hc⟩ := ProFiltPseuNormGrp₁.exhaustive _ a,
    refine ⟨c, λ _, ⟨a,hc⟩, _, rfl⟩,
    apply continuous_of_discrete_topology
  end⟩,
  inv_fun := λ f, f.down.val punit.star,
  left_inv := λ t, rfl,
  right_inv := λ t, by { ext ⟨⟩, refl } }

-- move and rename
def rhs_helper_equiv' :
  S ≃ S.to_Condensed.val.obj (op Profinite.punit) :=
{ to_fun := λ s, ulift.up $ Profinite.pt s,
  inv_fun := λ s, (ulift.down s).1 punit.star,
  left_inv := λ t, rfl,
  right_inv := λ t, by { ext ⟨⟩, refl } }

lemma rhs_helper₄ {α : Type u} [fintype α]
  (A : ProFiltPseuNormGrp₁.{u})
  (X : α → Profinite.{u})
  (e : Π (a : α),
    (CompHausFiltPseuNormGrp.to_Condensed.obj
    (CHFPNG₁_to_CHFPNGₑₗ.obj
      (PFPNG₁_to_CHFPNG₁ₑₗ.obj A))).val.obj (op $ X a))
  (a₀ : α) (x₀ : X a₀) :
  ((Condensed.val_obj_sigma_add_equiv X _).symm e).down.val ⟨a₀,x₀⟩ =
  (e a₀).down.val x₀ :=
begin
  let B := Condensed_Ab_to_CondensedSet.obj
    (CompHausFiltPseuNormGrp.to_Condensed.obj
    (CHFPNG₁_to_CHFPNGₑₗ.obj
      (PFPNG₁_to_CHFPNG₁ₑₗ.obj A))) ,
  let e₀ : (X a₀).to_Condensed ⟶ B :=
    (Profinite.to_Condensed_equiv _ B).symm (e a₀),
  let ee : (Profinite.sigma X).to_Condensed ⟶ B :=
    (Profinite.to_Condensed_equiv _ B).symm ((Condensed.val_obj_sigma_add_equiv X _).symm e),
  apply_fun rhs_helper_equiv A,
  let s₀ : (X a₀).to_Condensed.val.obj (op Profinite.punit) :=
    rhs_helper_equiv' _ x₀,
  have : (rhs_helper_equiv A) ((e a₀).down.val x₀) =
    e₀.val.app _ s₀, refl,
  rw this,
  have : e₀ = (Profinite_to_Condensed.map (Profinite.sigma.ι X a₀)) ≫ ee,
  { dsimp only [e₀, ee], symmetry,
    apply _root_.Condensed.val_obj_sigma_add_equiv_symm_apply },
  rw this, refl,
end

lemma rhs_helper₃ (i : fin ⌊j⌋₊) :
  ((((S.free'_lift S.to_condensed_free_pfpng).val.app (op (S.pmz ⌊j⌋₊)))
    (((Condensed.val_obj_sigma_add_equiv (λ (f : ulift (fin ⌊j⌋₊ → sign_type)), S.pow ⌊j⌋₊)
      S.free').symm)
    (λ (f : ulift (fin ⌊j⌋₊ → sign_type)),
      ((proetale_topology.to_sheafify (S.to_Condensed.val ⋙ AddCommGroup.free')).app
      (op (S.pow ⌊j⌋₊)))
      (finsupp.single {down := Profinite.product.π (λ (i : fin ⌊j⌋₊), S) i}
        ↑(f.down i))))).down).1 x =
    (x.1.down i : ℤ) • (S.to_free_pfpng (x.2 i)).1 :=
begin
  erw Profinite.free'_lift_val_obj_sigma_equiv_symm,
  simp only [← comp_apply],
  erw [free'_lift_app_eq'],
  simp only [continuous_map.to_fun_eq_coe, linear_map.to_add_monoid_hom_coe, finsupp.lift_apply,
  Profinite.to_condensed_free_pfpng_app, finsupp.sum_single_index, zero_smul, subtype.val_eq_coe],
  -- This is now very close...
  let Q := Condensed.val_obj_sigma_add_equiv (λ (a : ulift (fin ⌊j⌋₊ → sign_type)), S.pow ⌊j⌋₊)
    S.condensed_free_pfpng,
  change (Q.symm _).down.1 _ = _,
  cases x with x1 x2,
  erw rhs_helper₄,
  refl,
end

lemma rhs_helper₂ (i : fin ⌊j⌋₊) : (S.free_pfpng_π T)
  (((((S.free'_lift S.to_condensed_free_pfpng).val.app (op (S.pmz ⌊j⌋₊)))
    (((Condensed.val_obj_sigma_add_equiv (λ (f : ulift (fin ⌊j⌋₊ → sign_type)), S.pow ⌊j⌋₊)
      S.free').symm)
    (λ (f : ulift (fin ⌊j⌋₊ → sign_type)),
      ((proetale_topology.to_sheafify (S.to_Condensed.val ⋙ AddCommGroup.free')).app
      (op (S.pow ⌊j⌋₊)))
      (finsupp.single {down := Profinite.product.π (λ (i : fin ⌊j⌋₊), S) i}
        ↑(f.down i))))).down).1 x) =
  pi.single (T.proj (x.snd i)) ↑(x.fst.down i) :=
begin
  rw rhs_helper₃,
  erw (S.free_pfpng_π T).to_add_monoid_hom.map_zsmul,
  change
    _ • (((S.to_free_pfpng) ≫ (ProFiltPseuNormGrp₁.level.obj 1).map (S.free_pfpng_π T)) _).val = _,
  dsimp [Profinite.to_free_pfpng, Profinite.free_pfpng_π,
    Profinite.free_pfpng_level_iso],
  dsimp [limits.is_limit.cone_point_unique_up_to_iso],
  erw ← comp_apply,
  erw ← comp_apply,
  erw limits.is_limit.fac,
  erw limits.is_limit.fac,
  dsimp [Fintype.free_pfpng_unit, Profinite.as_limit_cone],
  ext t, erw pi.single_apply, split_ifs; simp,
  { intros hh, exact false.elim (hh h.symm) },
  { intros hh, exact false.elim (h hh.symm) },
end

lemma rhs_helper :
  (S.free_pfpng_π T)
  ((((S.free'_lift S.to_condensed_free_pfpng).val.app (op (S.pmz ⌊j⌋₊)))
  ((S.pmz_to_free' ⌊j⌋₊).val.app (op (S.pmz ⌊j⌋₊)) {down := 𝟙 (S.pmz ⌊j⌋₊)})).1.1 x) =
  ∑ i : fin ⌊j⌋₊, pi.single (T.proj (x.2 i)) (x.1.down i : ℤ) :=
begin
  dsimp [Profinite.pmz_to_free'],
  rw [category_theory.functor.map_id, id_apply],
  simp only [add_monoid_hom.map_sum],
  rw [rhs_helper₁],
  rw [add_equiv.map_sum, add_monoid_hom.map_sum],
  have := _root_.CompHausFiltPseuNormGrp.to_Condensed_app_sum_apply ⌊j⌋₊ _ _ _ x,
  dsimp at this, erw this, clear this,
  erw (S.free_pfpng_π T).to_add_monoid_hom.map_sum,
  congr' 1, funext i, dsimp,
  erw rhs_helper₂,
end

lemma key (j : (ulift.{u+1} nnreal)) :
  Profinite_to_Condensed.map (S.pmz_to_free_pfpng j.down) ≫
    (CHFPNG₁_to_CHFPNGₑₗ.obj
    (PFPNG₁_to_CHFPNG₁ₑₗ.obj S.free_pfpng)).level_Condensed_diagram_cocone.ι.app j =
  S.pmz_to_free' ⌊j.down⌋₊ ≫
  Condensed_Ab_to_CondensedSet.map S.free'_to_condensed_free_pfpng :=
begin
  apply_fun Profinite.to_Condensed_equiv _ _,
  ext x : 3, dsimp at x,
  dsimp [CompHausFiltPseuNormGrp.level_Condensed_diagram_cocone,
    Profinite.free'_to_condensed_free_pfpng],
  apply free_pfpng_ext, intros T,
  erw lhs_helper, erw rhs_helper,
end

end Profinite.epi_free'_to_condensed_setup

instance Profinite.epi_free'_to_condensed_free_pfpng_of_nonempty
  (S : Profinite.{u}) [nonempty S] : epi S.free'_to_condensed_free_pfpng :=
begin
  apply faithful_reflects_epi (Condensed_Ab_to_CondensedSet),
  let E := CompHausFiltPseuNormGrp.level_Condensed_diagram_cocone
    (CHFPNG₁_to_CHFPNGₑₗ.obj
    ((PFPNG₁_to_CHFPNG₁ₑₗ.obj S.free_pfpng))),
  have hh : is_iso (limits.colimit.desc _ E),
  { change is_iso (CompHausFiltPseuNormGrp.colimit_to_Condensed_obj _),
    apply_instance },
  let hE : limits.is_colimit E := @limits.is_colimit.of_point_iso
    _ _ _ _ _ _ _ _ hh, -- <-- move this
  apply category_theory.epi_to_colimit_of_exists  _ E hE,
  intros j,
  let j' : nnreal := ulift.down j,
  use [(S.pmz ⌊j'⌋₊).to_Condensed, S.pmz_to_free' ⌊j'⌋₊,
    Profinite_to_Condensed.map (S.pmz_to_free_pfpng j')],
  split,
  { apply epi_Profinite_to_Condensed_map_of_epi },
  { apply Profinite.epi_free'_to_condensed_setup.key },
end


import pseudo_normed_group.profinitely_filtered
/-!

# Profinitely filtered pseudo-normed groups with T⁻¹

The definition of `profinitely_filtered_pseudo_normed_group_with_Tinv`,
and morphisms between them.

-/
open pseudo_normed_group profinitely_filtered_pseudo_normed_group
  comphaus_filtered_pseudo_normed_group
open_locale nnreal big_operators

local attribute [instance] type_pow

class comphaus_filtered_pseudo_normed_group_with_Tinv (r' : out_param $ ℝ≥0) (M : Type*)
  extends comphaus_filtered_pseudo_normed_group M :=
(Tinv : comphaus_filtered_pseudo_normed_group_hom M M)
(Tinv_mem_filtration : ∀ c x, x ∈ filtration c → Tinv x ∈ filtration (r'⁻¹ * c))

/-- A *profinitely filtered pseudo-normed topological group with action by `T⁻¹`* is
a profinitely filtered pseudo-normed topological group `M` together with a
nonnegative real `r'` and homomorphism `Tinv : M → M` such that
`Tinv x ∈ filtration M (r'⁻¹ * c)` for all `x ∈ filtration M c`.
-/
class profinitely_filtered_pseudo_normed_group_with_Tinv (r' : out_param $ ℝ≥0) (M : Type*)
  extends profinitely_filtered_pseudo_normed_group M :=
(Tinv : comphaus_filtered_pseudo_normed_group_hom M M)
(Tinv_mem_filtration : ∀ c x, x ∈ filtration c → Tinv x ∈ filtration (r'⁻¹ * c))

namespace profinitely_filtered_pseudo_normed_group_with_Tinv

variables {r' : ℝ≥0} {M M₁ M₂ M₃ : Type*}
variables [profinitely_filtered_pseudo_normed_group_with_Tinv r' M]
variables [profinitely_filtered_pseudo_normed_group_with_Tinv r' M₁]
variables [profinitely_filtered_pseudo_normed_group_with_Tinv r' M₂]
variables [profinitely_filtered_pseudo_normed_group_with_Tinv r' M₃]

lemma aux {r' c c₂ : ℝ≥0} (h : c ≤ r' * c₂) : r'⁻¹ * c ≤ c₂ :=
begin
  by_cases hr' : r' = 0,
  { subst r', rw [inv_zero, zero_mul], exact zero_le' },
  { rwa [nnreal.mul_le_iff_le_inv, inv_inv], exact inv_ne_zero hr' }
end

@[simps]
def Tinv₀ (c c₂ : ℝ≥0) [h : fact (c ≤ r' * c₂)] (x : filtration M c) : filtration M c₂ :=
⟨Tinv (x : M), filtration_mono (aux h.1) (Tinv_mem_filtration _ _ x.2)⟩

lemma Tinv₀_continuous (c c₂ : ℝ≥0) [fact (c ≤ r' * c₂)] :
  continuous (@Tinv₀ r' M _ c c₂ _) :=
Tinv.continuous _ $ λ x, rfl

lemma Tinv_bound_by : (@Tinv _ M _).bound_by (r'⁻¹) := Tinv_mem_filtration

instance to_comphaus_filtered_pseudo_normed_group_with_Tinv
  (M : Type*) [profinitely_filtered_pseudo_normed_group_with_Tinv r' M] :
  comphaus_filtered_pseudo_normed_group_with_Tinv r' M :=
{ ..(infer_instance : profinitely_filtered_pseudo_normed_group_with_Tinv r' M) }

end profinitely_filtered_pseudo_normed_group_with_Tinv

section
set_option old_structure_cmd true

open comphaus_filtered_pseudo_normed_group_with_Tinv

/-- The type of strict morphisms between two compact Hausdorff filtered pseudo-normed groups
with an action of T⁻¹. -/
structure comphaus_filtered_pseudo_normed_group_with_Tinv_hom (r' : ℝ≥0) (M₁ M₂ : Type*)
  [comphaus_filtered_pseudo_normed_group_with_Tinv r' M₁]
  [comphaus_filtered_pseudo_normed_group_with_Tinv r' M₂]
  extends M₁ →+ M₂ :=
(strict' : ∀ ⦃c x⦄, x ∈ filtration M₁ c → to_fun x ∈ filtration M₂ c)
(continuous' : ∀ c, continuous (pseudo_normed_group.level to_fun strict' c))
(map_Tinv' : ∀ x, to_fun (Tinv x) = Tinv (to_fun x))

end

attribute [nolint doc_blame] comphaus_filtered_pseudo_normed_group_with_Tinv_hom.mk
  comphaus_filtered_pseudo_normed_group_with_Tinv_hom.to_add_monoid_hom

namespace comphaus_filtered_pseudo_normed_group_with_Tinv_hom

open comphaus_filtered_pseudo_normed_group_with_Tinv

variables {r' : ℝ≥0} {M M₁ M₂ M₃ : Type*}
variables [comphaus_filtered_pseudo_normed_group_with_Tinv r' M]
variables [comphaus_filtered_pseudo_normed_group_with_Tinv r' M₁]
variables [comphaus_filtered_pseudo_normed_group_with_Tinv r' M₂]
variables [comphaus_filtered_pseudo_normed_group_with_Tinv r' M₃]
variables (f g : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂)

instance : has_coe_to_fun (comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂)
  (λ _, M₁ → M₂):=
⟨comphaus_filtered_pseudo_normed_group_with_Tinv_hom.to_fun⟩

@[simp] lemma coe_mk (f) (h₁) (h₂) (h₃) (h₄) (h₅) :
  ⇑(⟨f, h₁, h₂, h₃, h₄, h₅⟩ : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂) = f :=
rfl

@[simp] lemma mk_to_monoid_hom (f) (h₁) (h₂) (h₃) (h₄) (h₅) :
  (⟨f, h₁, h₂, h₃, h₄, h₅⟩ :
    comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂).to_add_monoid_hom =
    ⟨f, h₁, h₂⟩ := rfl

@[simp] lemma coe_to_add_monoid_hom : ⇑f.to_add_monoid_hom = f := rfl

@[simp] lemma map_zero : f 0 = 0 := f.to_add_monoid_hom.map_zero

@[simp] lemma map_add (x y) : f (x + y) = f x + f y := f.to_add_monoid_hom.map_add _ _

@[simp] lemma map_sum {ι : Type*} (x : ι → M₁) (s : finset ι) :
  f (∑ i in s, x i) = ∑ i in s, f (x i) :=
f.to_add_monoid_hom.map_sum _ _

@[simp] lemma map_sub (x y) : f (x - y) = f x - f y := f.to_add_monoid_hom.map_sub _ _

@[simp] lemma map_neg (x) : f (-x) = -(f x) := f.to_add_monoid_hom.map_neg _

@[simp] lemma map_zsmul (n : ℤ) (x) : f (n • x) = n • (f x) := f.to_add_monoid_hom.map_zsmul _ _

lemma strict : ∀ ⦃c x⦄, x ∈ filtration M₁ c → f x ∈ filtration M₂ c := f.strict'

/-- `f.level c` is the function `filtration M₁ c → filtration M₂ c`
induced by a `comphaus_filtered_pseudo_normed_group_with_Tinv_hom M₁ M₂`. -/
@[simps] def level : ∀ (c : ℝ≥0), filtration M₁ c → filtration M₂ c :=
pseudo_normed_group.level f f.strict

lemma level_continuous (c : ℝ≥0) : continuous (f.level c) := f.continuous' c

lemma map_Tinv (x : M₁) : f (Tinv x) = Tinv (f x) := f.map_Tinv' x

variables {f g}

@[ext] theorem ext (H : ∀ x, f x = g x) : f = g :=
by cases f; cases g; congr'; exact funext H

instance : has_zero (comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂) :=
⟨{ strict' := λ c x h, zero_mem_filtration _,
   continuous' := λ c, @continuous_const _ (filtration M₂ c) _ _ 0,
   map_Tinv' := λ x, show 0 = Tinv (0 : M₂), from Tinv.map_zero.symm,
   .. (0 : M₁ →+ M₂) }⟩

instance : inhabited (comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂) := ⟨0⟩

lemma coe_inj ⦃f g : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂⦄
  (h : (f : M₁ → M₂) = g) :
  f = g :=
by cases f; cases g; cases h; refl

/-- The identity function as `comphaus_filtered_pseudo_normed_group_with_Tinv_hom`. -/
@[simps] def id : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M M :=
{ strict' := λ c x, id,
  continuous' := λ c, by { convert continuous_id, ext, refl },
  map_Tinv' := λ x, rfl,
  .. add_monoid_hom.id _ }

/-- The composition of `comphaus_filtered_pseudo_normed_group_with_Tinv_hom`s. -/
@[simps] def comp
  (g : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₂ M₃)
  (f : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂) :
  comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₃ :=
{ strict' := λ c x hx, g.strict (f.strict hx),
  continuous' := λ c, (g.level_continuous c).comp (f.level_continuous c),
  map_Tinv' := λ x,
  calc g (f (Tinv x)) = g (Tinv (f x)) : by rw f.map_Tinv
                  ... = Tinv (g (f x)) : by rw g.map_Tinv,
  .. (g.to_add_monoid_hom.comp f.to_add_monoid_hom) }

variables (f)

/-- The `comphaus_filtered_pseudo_normed_group_hom` underlying a
`comphaus_filtered_pseudo_normed_group_with_Tinv_hom`. -/
def to_comphaus_filtered_pseudo_normed_group_hom :
  comphaus_filtered_pseudo_normed_group_hom M₁ M₂ :=
comphaus_filtered_pseudo_normed_group_hom.mk_of_strict f.to_add_monoid_hom
(λ c, ⟨λ x h, f.strict h, f.level_continuous c⟩)

lemma to_profinitely_filtered_pseudo_normed_group_hom_strict :
  f.to_comphaus_filtered_pseudo_normed_group_hom.strict :=
comphaus_filtered_pseudo_normed_group_hom.mk_of_strict_strict _ _

variables {f}

def mk' (f : comphaus_filtered_pseudo_normed_group_hom M₁ M₂)
  (hf1 : f.bound_by 1) (hfT) :
  comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₁ M₂ :=
{ to_fun := f,
  strict' := λ c x hx, by simpa only [one_mul] using hf1 hx,
  continuous' := λ c, f.continuous _ (λ x, rfl),
  map_Tinv' := hfT,
  .. f }

@[simp] lemma mk'_apply
  (f : comphaus_filtered_pseudo_normed_group_hom M₁ M₂) (hf1) (hfT) (x : M₁) :
  @mk' r' _ _ _ _ f hf1 hfT x = f x := rfl

/-- If the inverse of `comphaus_filtered_pseudo_normed_group_with_Tinv_hom` is strict, then it
is a `comphaus_filtered_pseudo_normed_group_with_Tinv_hom`. -/
def inv_of_equiv_of_strict (e : M₁ ≃+ M₂) (he : ∀ x, f x = e x)
  (strict : ∀ ⦃c x⦄, x ∈ filtration M₂ c → e.symm x ∈ filtration M₁ c) :
  comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' M₂ M₁ :=
{ strict' := strict,
  continuous' := λ c,
  begin
    simp only [add_equiv.coe_to_add_monoid_hom, add_monoid_hom.to_fun_eq_coe],
    have hcont := f.continuous' c,
    let g : (filtration M₁ c) ≃ (filtration M₂ c) :=
    ⟨λ x, ⟨f x, f.strict x.2⟩, λ x, ⟨e.symm x, strict x.2⟩, λ x, by simp [he], λ x, by simp [he]⟩,
    change continuous g.symm,
    rw continuous_iff_is_closed,
    intros U hU,
    rw [← g.image_eq_preimage],
    exact (hcont.closed_embedding g.injective).is_closed_map U hU,
  end,
  map_Tinv' := λ x,
  begin
    apply e.injective,
    simp only [add_equiv.coe_to_add_monoid_hom, add_monoid_hom.to_fun_eq_coe],
    rw [e.apply_symm_apply, ← he, map_Tinv, he, e.apply_symm_apply],
  end,
  .. e.symm.to_add_monoid_hom }

@[simp]
lemma inv_of_equiv_of_strict.apply (x : M₁) (e : M₁ ≃+ M₂) (he : ∀ x, f x = e x)
  (strict : ∀ ⦃c x⦄, x ∈ filtration M₂ c → e.symm x ∈ filtration M₁ c) :
  (inv_of_equiv_of_strict e he strict) (f x) = x := by simp [inv_of_equiv_of_strict, he]

@[simp]
lemma inv_of_equiv_of_strict_symm.apply (x : M₂) (e : M₁ ≃+ M₂) (he : ∀ x, f x = e x)
  (strict : ∀ ⦃c x⦄, x ∈ filtration M₂ c → e.symm x ∈ filtration M₁ c) :
  f (inv_of_equiv_of_strict e he strict x) = x := by simp [inv_of_equiv_of_strict, he]

end comphaus_filtered_pseudo_normed_group_with_Tinv_hom

namespace punit

instance profinitely_filtered_pseudo_normed_group_with_Tinv (r' : ℝ≥0) :
  profinitely_filtered_pseudo_normed_group_with_Tinv r' punit :=
{ Tinv := comphaus_filtered_pseudo_normed_group_hom.id,
  Tinv_mem_filtration := λ c x h, set.mem_univ _,
  .. punit.profinitely_filtered_pseudo_normed_group }

end punit

namespace profinitely_filtered_pseudo_normed_group_with_Tinv

section
-- TODO: Generalize this section to `comphaus_filtered...` as needed.
/-! ## Powers -/

noncomputable theory

variables (r' : ℝ≥0) {ι : Type*} (M M₁ M₂ : ι → Type*)
variables [Π i, profinitely_filtered_pseudo_normed_group_with_Tinv r' (M i)]
variables [Π i, profinitely_filtered_pseudo_normed_group_with_Tinv r' (M₁ i)]
variables [Π i, profinitely_filtered_pseudo_normed_group_with_Tinv r' (M₂ i)]

instance pi : profinitely_filtered_pseudo_normed_group_with_Tinv r' (Π i, M i) :=
{ Tinv := comphaus_filtered_pseudo_normed_group.pi_map (λ i, Tinv)
    ⟨r'⁻¹, λ i, Tinv_bound_by⟩,
  Tinv_mem_filtration := λ c x hx i, Tinv_mem_filtration _ _ (hx i),
  .. profinitely_filtered_pseudo_normed_group.pi _ }

instance pi' (M : Type*) [profinitely_filtered_pseudo_normed_group_with_Tinv r' M] (N : ℕ) :
  profinitely_filtered_pseudo_normed_group_with_Tinv r' (M^N) :=
profinitely_filtered_pseudo_normed_group_with_Tinv.pi r' (λ i, M)

include r'
@[simp] lemma pi_Tinv_apply (x : Π i, M i) (i : ι) : Tinv x i = Tinv (x i) := rfl
omit r'

@[simps {fully_applied := ff}]
def pi_proj (i : ι) : comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' (Π i, M i) (M i) :=
{ to_fun := pi.eval_add_monoid_hom M i,
  strict' := λ c x hx, hx i,
  continuous' := λ c, (continuous_apply i).comp (filtration_pi_homeo M c).continuous,
  map_Tinv' := λ x, rfl,
  .. pi.eval_add_monoid_hom M i }

/-- Universal property of the product of
profinitely filtered pseudo-normed groups with `T⁻¹`-action -/
@[simps {fully_applied := ff}]
def pi_lift {N : Type*} [profinitely_filtered_pseudo_normed_group_with_Tinv r' N]
  (f : Π i, comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' N (M i)) :
  comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' N (Π i, M i) :=
{ to_fun := add_monoid_hom.mk_to_pi (λ i, (f i).to_add_monoid_hom),
  strict' := λ c x hx i, (f i).strict hx,
  continuous' :=
  begin
    intros c,
    rw continuous_induced_rng,
    apply continuous_pi,
    intro i,
    exact (f i).continuous' c,
  end,
  map_Tinv' := λ x, by { ext i, exact (f i).map_Tinv x },
  .. add_monoid_hom.mk_to_pi (λ i, (f i).to_add_monoid_hom) }

@[simps {fully_applied := ff}]
def pi_map (f : Π i, comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' (M₁ i) (M₂ i)) :
  comphaus_filtered_pseudo_normed_group_with_Tinv_hom r' (Π i, M₁ i) (Π i, M₂ i) :=
pi_lift r' _ $ λ i, (f i).comp (pi_proj r' _ i)

end

end profinitely_filtered_pseudo_normed_group_with_Tinv