/-
Copyright (c) 2020 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel, Scott Morrison

! This file was ported from Lean 3 source module category_theory.preadditive.projective
! leanprover-community/mathlib commit f8d8465c3c392a93b9ed226956e26dee00975946
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Homology.Exact
import Mathbin.CategoryTheory.Limits.Shapes.Biproducts
import Mathbin.CategoryTheory.Adjunction.Limits
import Mathbin.CategoryTheory.Limits.Preserves.Finite

/-!
# Projective objects and categories with enough projectives

An object `P` is called projective if every morphism out of `P` factors through every epimorphism.

A category `C` has enough projectives if every object admits an epimorphism from some
projective object.

`projective.over X` picks an arbitrary such projective object,
and `projective.π X : projective.over X ⟶ X` is the corresponding epimorphism.

Given a morphism `f : X ⟶ Y`, `projective.left f` is a projective object over `kernel f`,
and `projective.d f : projective.left f ⟶ X` is the morphism `π (kernel f) ≫ kernel.ι f`.
-/

noncomputable section

open CategoryTheory

open CategoryTheory.Limits

open Opposite

universe v u

namespace CategoryTheory

variable {C : Type u} [Category.{v} C]

/--
An object `P` is called projective if every morphism out of `P` factors through every epimorphism.
-/
class Projective (P : C) : Prop where
  Factors : ∀ {E X : C} (f : P ⟶ X) (e : E ⟶ X) [Epi e], ∃ f', f' ≫ e = f
#align category_theory.projective CategoryTheory.Projective

section

/-- A projective presentation of an object `X` consists of an epimorphism `f : P ⟶ X`
from some projective object `P`.
-/
@[nolint has_nonempty_instance]
structure ProjectivePresentation (X : C) where
  p : C
  Projective : Projective P := by infer_instance
  f : P ⟶ X
  Epi : Epi f := by infer_instance
#align category_theory.projective_presentation CategoryTheory.ProjectivePresentation

attribute [instance] projective_presentation.projective projective_presentation.epi

variable (C)

/-- A category "has enough projectives" if for every object `X` there is a projective object `P` and
    an epimorphism `P ↠ X`. -/
class EnoughProjectives : Prop where
  presentation : ∀ X : C, Nonempty (ProjectivePresentation X)
#align category_theory.enough_projectives CategoryTheory.EnoughProjectives

end

namespace Projective

/--
An arbitrarily chosen factorisation of a morphism out of a projective object through an epimorphism.
-/
def factorThru {P X E : C} [Projective P] (f : P ⟶ X) (e : E ⟶ X) [Epi e] : P ⟶ E :=
  (Projective.factors f e).some
#align category_theory.projective.factor_thru CategoryTheory.Projective.factorThru

@[simp]
theorem factorThru_comp {P X E : C} [Projective P] (f : P ⟶ X) (e : E ⟶ X) [Epi e] :
    factorThru f e ≫ e = f :=
  (Projective.factors f e).choose_spec
#align category_theory.projective.factor_thru_comp CategoryTheory.Projective.factorThru_comp

section

open ZeroObject

instance zero_projective [HasZeroObject C] [HasZeroMorphisms C] : Projective (0 : C)
    where Factors E X f e epi := by
    use 0
    ext
#align category_theory.projective.zero_projective CategoryTheory.Projective.zero_projective

end

theorem of_iso {P Q : C} (i : P ≅ Q) (hP : Projective P) : Projective Q :=
  by
  fconstructor
  intro E X f e e_epi
  obtain ⟨f', hf'⟩ := projective.factors (i.hom ≫ f) e
  exact ⟨i.inv ≫ f', by simp [hf']⟩
#align category_theory.projective.of_iso CategoryTheory.Projective.of_iso

theorem iso_iff {P Q : C} (i : P ≅ Q) : Projective P ↔ Projective Q :=
  ⟨of_iso i, of_iso i.symm⟩
#align category_theory.projective.iso_iff CategoryTheory.Projective.iso_iff

/-- The axiom of choice says that every type is a projective object in `Type`. -/
instance (X : Type u) : Projective X
    where Factors E X' f e epi :=
    ⟨fun x => ((epi_iff_surjective _).mp epi (f x)).some,
      by
      ext x
      exact ((epi_iff_surjective _).mp epi (f x)).choose_spec⟩

instance Type.enoughProjectives : EnoughProjectives (Type u)
    where presentation X :=
    ⟨{  p := X
        f := 𝟙 X }⟩
#align category_theory.projective.Type.enough_projectives CategoryTheory.Projective.Type.enoughProjectives

instance {P Q : C} [HasBinaryCoproduct P Q] [Projective P] [Projective Q] : Projective (P ⨿ Q)
    where Factors E X' f e epi :=
    ⟨coprod.desc (factor_thru (coprod.inl ≫ f) e) (factor_thru (coprod.inr ≫ f) e), by tidy⟩

section

attribute [local tidy] tactic.discrete_cases

instance {β : Type v} (g : β → C) [HasCoproduct g] [∀ b, Projective (g b)] : Projective (∐ g)
    where Factors E X' f e epi := ⟨sigma.desc fun b => factor_thru (sigma.ι g b ≫ f) e, by tidy⟩

end

instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Projective P] [Projective Q] :
    Projective (P ⊞ Q)
    where Factors E X' f e epi :=
    ⟨biprod.desc (factor_thru (biprod.inl ≫ f) e) (factor_thru (biprod.inr ≫ f) e), by tidy⟩

instance {β : Type v} (g : β → C) [HasZeroMorphisms C] [HasBiproduct g] [∀ b, Projective (g b)] :
    Projective (⨁ g)
    where Factors E X' f e epi :=
    ⟨biproduct.desc fun b => factor_thru (biproduct.ι g b ≫ f) e, by tidy⟩

theorem projective_iff_preservesEpimorphisms_coyoneda_obj (P : C) :
    Projective P ↔ (coyoneda.obj (op P)).PreservesEpimorphisms :=
  ⟨fun hP =>
    ⟨fun X Y f hf =>
      (epi_iff_surjective _).2 fun g =>
        have : Projective (unop (op P)) := hP
        ⟨factor_thru g f, factor_thru_comp _ _⟩⟩,
    fun h =>
    ⟨fun E X f e he =>
      (epi_iff_surjective _).1 (inferInstance : epi ((coyoneda.obj (op P)).map e)) f⟩⟩
#align category_theory.projective.projective_iff_preserves_epimorphisms_coyoneda_obj CategoryTheory.Projective.projective_iff_preservesEpimorphisms_coyoneda_obj

section EnoughProjectives

variable [EnoughProjectives C]

/-- `projective.over X` provides an arbitrarily chosen projective object equipped with
an epimorphism `projective.π : projective.over X ⟶ X`.
-/
def over (X : C) : C :=
  (EnoughProjectives.presentation X).some.p
#align category_theory.projective.over CategoryTheory.Projective.over

instance projective_over (X : C) : Projective (over X) :=
  (EnoughProjectives.presentation X).some.Projective
#align category_theory.projective.projective_over CategoryTheory.Projective.projective_over

/-- The epimorphism `projective.π : projective.over X ⟶ X`
from the arbitrarily chosen projective object over `X`.
-/
def π (X : C) : over X ⟶ X :=
  (EnoughProjectives.presentation X).some.f
#align category_theory.projective.π CategoryTheory.Projective.π

instance π_epi (X : C) : Epi (π X) :=
  (EnoughProjectives.presentation X).some.Epi
#align category_theory.projective.π_epi CategoryTheory.Projective.π_epi

section

variable [HasZeroMorphisms C] {X Y : C} (f : X ⟶ Y) [HasKernel f]

/-- When `C` has enough projectives, the object `projective.syzygies f` is
an arbitrarily chosen projective object over `kernel f`.
-/
def syzygies : C :=
  over (kernel f)deriving Projective
#align category_theory.projective.syzygies CategoryTheory.Projective.syzygies

/-- When `C` has enough projectives,
`projective.d f : projective.syzygies f ⟶ X` is the composition
`π (kernel f) ≫ kernel.ι f`.

(When `C` is abelian, we have `exact (projective.d f) f`.)
-/
abbrev d : syzygies f ⟶ X :=
  π (kernel f) ≫ kernel.ι f
#align category_theory.projective.d CategoryTheory.Projective.d

end

end EnoughProjectives

end Projective

namespace Adjunction

variable {D : Type _} [Category D] {F : C ⥤ D} {G : D ⥤ C}

theorem map_projective (adj : F ⊣ G) [G.PreservesEpimorphisms] (P : C) (hP : Projective P) :
    Projective (F.obj P) :=
  ⟨fun X Y f g => by
    intro
    rcases hP.factors (adj.unit.app P ≫ G.map f) (G.map g) with ⟨⟩
    use F.map w ≫ adj.counit.app X
    rw [category.assoc, ← adjunction.counit_naturality, ← category.assoc, ← F.map_comp, h]
    simp⟩
#align category_theory.adjunction.map_projective CategoryTheory.Adjunction.map_projective

theorem projective_of_map_projective (adj : F ⊣ G) [Full F] [Faithful F] (P : C)
    (hP : Projective (F.obj P)) : Projective P :=
  ⟨fun X Y f g => by
    intro
    haveI := adj.left_adjoint_preserves_colimits
    rcases(@hP).1 (F.map f) (F.map g) with ⟨⟩
    use adj.unit.app _ ≫ G.map w ≫ (inv <| adj.unit.app _)
    refine' faithful.map_injective F _
    simpa⟩
#align category_theory.adjunction.projective_of_map_projective CategoryTheory.Adjunction.projective_of_map_projective

/-- Given an adjunction `F ⊣ G` such that `G` preserves epis, `F` maps a projective presentation of
`X` to a projective presentation of `F(X)`. -/
def mapProjectivePresentation (adj : F ⊣ G) [G.PreservesEpimorphisms] (X : C)
    (Y : ProjectivePresentation X) : ProjectivePresentation (F.obj X)
    where
  p := F.obj Y.p
  Projective := adj.map_projective _ Y.Projective
  f := F.map Y.f
  Epi := by haveI := adj.left_adjoint_preserves_colimits <;> infer_instance
#align category_theory.adjunction.map_projective_presentation CategoryTheory.Adjunction.mapProjectivePresentation

end Adjunction

namespace Equivalence

variable {D : Type _} [Category D] (F : C ≌ D)

/-- Given an equivalence of categories `F`, a projective presentation of `F(X)` induces a
projective presentation of `X.` -/
def projectivePresentationOfMapProjectivePresentation (X : C)
    (Y : ProjectivePresentation (F.Functor.obj X)) : ProjectivePresentation X
    where
  p := F.inverse.obj Y.p
  Projective := Adjunction.map_projective F.symm.toAdjunction Y.p Y.Projective
  f := F.inverse.map Y.f ≫ F.unitInv.app _
  Epi := epi_comp _ _
#align category_theory.equivalence.projective_presentation_of_map_projective_presentation CategoryTheory.Equivalence.projectivePresentationOfMapProjectivePresentation

theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D :=
  by
  constructor
  all_goals intro H; constructor; intro X; constructor
  ·
    exact
      F.symm.projective_presentation_of_map_projective_presentation _
        (Nonempty.some (H.presentation (F.inverse.obj X)))
  ·
    exact
      F.projective_presentation_of_map_projective_presentation X
        (Nonempty.some (H.presentation (F.functor.obj X)))
#align category_theory.equivalence.enough_projectives_iff CategoryTheory.Equivalence.enoughProjectives_iff

end Equivalence

open Projective

section

variable [HasZeroMorphisms C] [HasEqualizers C] [HasImages C]

/-- Given a projective object `P` mapping via `h` into
the middle object `R` of a pair of exact morphisms `f : Q ⟶ R` and `g : R ⟶ S`,
such that `h ≫ g = 0`, there is a lift of `h` to `Q`.
-/
def Exact.lift {P Q R S : C} [Projective P] (h : P ⟶ R) (f : Q ⟶ R) (g : R ⟶ S) (hfg : Exact f g)
    (w : h ≫ g = 0) : P ⟶ Q :=
  factorThru (factorThru (factorThruKernelSubobject g h w) (imageToKernel f g hfg.w))
    (factorThruImageSubobject f)
#align category_theory.exact.lift CategoryTheory.Exact.lift

@[simp]
theorem Exact.lift_comp {P Q R S : C} [Projective P] (h : P ⟶ R) (f : Q ⟶ R) (g : R ⟶ S)
    (hfg : Exact f g) (w : h ≫ g = 0) : Exact.lift h f g hfg w ≫ f = h :=
  by
  simp [exact.lift]
  conv_lhs =>
    congr
    skip
    rw [← image_subobject_arrow_comp f]
  rw [← category.assoc, factor_thru_comp, ← imageToKernel_arrow, ← category.assoc,
    CategoryTheory.Projective.factorThru_comp, factor_thru_kernel_subobject_comp_arrow]
#align category_theory.exact.lift_comp CategoryTheory.Exact.lift_comp

end

end CategoryTheory


import tactic

import group_theory.index
import group_theory.p_group
import group_theory.quotient_group
import group_theory.coset
import group_theory.specific_groups.cyclic
import group_theory.abelianization
import data.finite.basic
import data.finite.card

open fintype
open is_p_group
open group

/-- A group that is commutative can be turned into a comm_group
(See https://github.com/leanprover-community/mathlib/pull/14960#issuecomment-1178880188)
-/
instance {G} : can_lift (group G) (comm_group G) :=
{ coe := @comm_group.to_group G,
  cond := λ g, by exactI (∀ x y : G, commute x y),
  prf := λ g hg, ⟨{mul_comm := hg, ..g}, by cases g; refl⟩ }

/-- My lemma -/
lemma group.center_eq_top_of_comm {H : Type*} [group H] (h : ∀ a b : H, a * b = b * a) : subgroup.center H = ⊤ :=
begin
  rw subgroup.eq_top_iff',
  intros x y,
  exact (h y x),
end

lemma group.of_comm_center_eq_top {H : Type*} [group H] (h : (subgroup.center H = ⊤)) : (∀ a b : H, a * b = b * a) :=
begin
  rw subgroup.eq_top_iff' at h,
  intros x y,
  rw (h x),
end

variables (p : ℕ) [fact (nat.prime p)]
variables (G : Type*) [fintype G] [group G]

def order_psq : Prop := card G = p^2

namespace order_psq

lemma has_ord_psq : order_psq p G → ∃ q : ℕ , card G = q^2 :=
begin
  intro h1,
  use p,
  apply h1,
end

section G_has_order_psq

variables (hG : order_psq p G)
include hG

lemma p_group : is_p_group p G :=
begin
  exact of_card hG,
end

lemma psq_center_nontrivial [nontrivial G] : nontrivial (subgroup.center G) :=
center_nontrivial (p_group p G hG)

open_locale classical

@[instance] def quotient_with_center_is_fintype : finite (G ⧸ subgroup.center G) :=
infer_instance

lemma center_index_not_prime : ¬ nat.prime (fintype.card (G ⧸ subgroup.center G)) :=
begin
  intro h1,
  haveI : fact(nat.prime (card (G ⧸ subgroup.center G))) := ⟨h1⟩,
  haveI := is_cyclic_of_prime_card (rfl : card (G ⧸ subgroup.center G) = _),
  have h2 := commutative_of_cyclic_center_quotient (quotient_group.mk' (subgroup.center G)) (by simp),
  have h4 : card (G ⧸ subgroup.center G) = 1,
  {
    simp_rw [group.center_eq_top_of_comm h2, ← nat.card_eq_fintype_card],
    exact subgroup.index_top,
  },
  rw h4 at h1,
  exact nat.not_prime_one h1,
end

lemma center_index_not_prime_2 : ¬ nat.prime (fintype.card (G ⧸ subgroup.center G)) :=
begin
  intro h1,
  haveI : fact(nat.prime (card (G ⧸ subgroup.center G))) := ⟨h1⟩,
  haveI := is_cyclic_of_prime_card (rfl : card (G ⧸ subgroup.center G) = _),
  --letI := comm_group_of_cycle_center_quotient (quotient_group.mk' (subgroup.center G)) (by simp),
  have h2 := commutative_of_cyclic_center_quotient (quotient_group.mk' (subgroup.center G)) (by simp),
  unfreezingI { lift ‹group G› to comm_group G using h2 },
  have h3 : subgroup.center G = ⊤,
  {
    exact comm_group.center_eq_top,  -- working
  },
  have h4 : card (G ⧸ subgroup.center G) = 1,
  {
    simp_rw [h3, ← nat.card_eq_fintype_card],
    exact subgroup.index_top,
  },
  rw h4 at h1,
  exact nat.not_prime_one h1,
end

theorem order_psq_are_abelian [nontrivial G] : (∀ x1 x2 : G, x1 * x2 = x2 * x1) :=
begin
  apply group.of_comm_center_eq_top,
  have h1 : (card (subgroup.center G) ∣ card (G)),
  {
    exact (subgroup.center G).card_subgroup_dvd_card,
  },
  have h2 : (card G = p^2),
  {
    exact hG,
  },
  rw h2 at h1,
  rw nat.dvd_prime_pow at h1,
  rcases h1 with ⟨k, hk1, hk2⟩,
  swap,
  apply fact.out,
  interval_cases k,
  {
    exfalso,
    have h31 : nontrivial (subgroup.center G),
    {
      exact center_nontrivial (p_group p G hG),
    },
    rw subgroup.nontrivial_iff_exists_ne_one at h31,
    sorry,
  },
  {
    exfalso,
    sorry,
  },
  {
    sorry,
  },
end

end G_has_order_psq

end order_psq


import Lean

def f : Nat → Bool
  | 0 => true
  | n + 1 => (match n with
    | 0 => true
    | _ + 1 => true) && f n

def g (i j : Nat) : Nat :=
  if i < 5 then 0 else
  match j with
  | Nat.zero => 1
  | Nat.succ j => g i j

def h (i j : Nat) : Nat :=
  i +
    match j with
    | Nat.zero => 1
    | Nat.succ j => h i j

def r (i j : Nat) : Nat :=
  i +
    match j with
    | Nat.zero => 1
    | Nat.succ j =>
      i * match j with
          | Nat.zero => 2
          | Nat.succ j => r i j

def s (i j : Nat) : Nat :=
  let z :=
    match j with
    | Nat.zero => i
    | Nat.succ j => s i j
  z + z

example : f 0 = true :=
  rfl

example : f (i+1) = ((match i with | 0 => true | _ + 1 => true) && f i) :=
  rfl

example : g i (j + 1) = if i < 5 then 0 else g i j :=
  rfl

example : g i 0 = if i < 5 then 0 else 1 :=
  rfl

example : h i 0 = i + 1 :=
  rfl

example : h i (j + 1) = i + h i j :=
  rfl

example : r i 0 = i + 1 :=
  rfl

example : r i 1 = i + i * 2 :=
  rfl

example : r i (j + 2) = i + i * r i j :=
  rfl

example : s i (j + 1) = let z := s i j; z + z :=
  rfl

open Lean
open Lean.Meta
open Lean.Elab
open Lean.Elab.Command
elab "unfold " e:term : command =>
  runTermElabM none fun xs => do
    let e ← instantiateMVars (← Term.withSynthesize <| Term.elabTerm e none)
    match (← unfoldDefinition? e) with
    | some e => logInfo m!"{e}"
    | none => throwError ""

section end

variable (i j : Nat)

unfold f 0
unfold f (i+1)
unfold g i 0
unfold g i (j+1)
unfold h i 0
unfold h i (j + 1)
unfold r i 0
unfold r i 1
unfold r i (j + 2)
unfold r i j.succ.succ
unfold s i (j + 1)


/-
Copyright (c) 2020 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 Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.topology.algebra.module
import Mathlib.linear_algebra.multilinear
import Mathlib.PostPort

universes u v w₁ w₂ l u_1 w₃ w₁' w₄ w u_2 u_3

namespace Mathlib

/-!
# Continuous multilinear maps

We define continuous multilinear maps as maps from `Π(i : ι), M₁ i` to `M₂` which are multilinear
and continuous, by extending the space of multilinear maps with a continuity assumption.
Here, `M₁ i` and `M₂` are modules over a ring `R`, and `ι` is an arbitrary type, and all these
spaces are also topological spaces.

## Main definitions

* `continuous_multilinear_map R M₁ M₂` is the space of continuous multilinear maps from
  `Π(i : ι), M₁ i` to `M₂`. We show that it is an `R`-module.

## Implementation notes

We mostly follow the API of multilinear maps.

## Notation

We introduce the notation `M [×n]→L[R] M'` for the space of continuous `n`-multilinear maps from
`M^n` to `M'`. This is a particular case of the general notion (where we allow varying dependent
types as the arguments of our continuous multilinear maps), but arguably the most important one,
especially when defining iterated derivatives.
-/

/-- Continuous multilinear maps over the ring `R`, from `Πi, M₁ i` to `M₂` where `M₁ i` and `M₂`
are modules over `R` with a topological structure. In applications, there will be compatibility
conditions between the algebraic and the topological structures, but this is not needed for the
definition. -/
structure continuous_multilinear_map (R : Type u) {ι : Type v} (M₁ : ι → Type w₁) (M₂ : Type w₂) [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂]
extends multilinear_map R M₁ M₂
where
  cont : continuous (multilinear_map.to_fun _to_multilinear_map)

namespace continuous_multilinear_map

protected instance has_coe_to_fun {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] : has_coe_to_fun (continuous_multilinear_map R M₁ M₂) :=
  has_coe_to_fun.mk (fun (f : continuous_multilinear_map R M₁ M₂) => ((i : ι) → M₁ i) → M₂)
    fun (f : continuous_multilinear_map R M₁ M₂) => multilinear_map.to_fun (to_multilinear_map f)

theorem coe_continuous {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) : continuous ⇑f :=
  cont f

@[simp] theorem coe_coe {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) : ⇑(to_multilinear_map f) = ⇑f :=
  rfl

theorem to_multilinear_map_inj {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] : function.injective to_multilinear_map := sorry

theorem ext {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {f : continuous_multilinear_map R M₁ M₂} {f' : continuous_multilinear_map R M₁ M₂} (H : ∀ (x : (i : ι) → M₁ i), coe_fn f x = coe_fn f' x) : f = f' :=
  to_multilinear_map_inj (multilinear_map.ext H)

@[simp] theorem map_add {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (m : (i : ι) → M₁ i) (i : ι) (x : M₁ i) (y : M₁ i) : coe_fn f (function.update m i (x + y)) = coe_fn f (function.update m i x) + coe_fn f (function.update m i y) :=
  multilinear_map.map_add' (to_multilinear_map f) m i x y

@[simp] theorem map_smul {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (m : (i : ι) → M₁ i) (i : ι) (c : R) (x : M₁ i) : coe_fn f (function.update m i (c • x)) = c • coe_fn f (function.update m i x) :=
  multilinear_map.map_smul' (to_multilinear_map f) m i c x

theorem map_coord_zero {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) {m : (i : ι) → M₁ i} (i : ι) (h : m i = 0) : coe_fn f m = 0 :=
  multilinear_map.map_coord_zero (to_multilinear_map f) i h

@[simp] theorem map_zero {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) [Nonempty ι] : coe_fn f 0 = 0 :=
  multilinear_map.map_zero (to_multilinear_map f)

protected instance has_zero {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] : HasZero (continuous_multilinear_map R M₁ M₂) :=
  { zero := mk (multilinear_map.mk (multilinear_map.to_fun 0) sorry sorry) sorry }

protected instance inhabited {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] : Inhabited (continuous_multilinear_map R M₁ M₂) :=
  { default := 0 }

@[simp] theorem zero_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (m : (i : ι) → M₁ i) : coe_fn 0 m = 0 :=
  rfl

protected instance has_add {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [has_continuous_add M₂] : Add (continuous_multilinear_map R M₁ M₂) :=
  { add :=
      fun (f f' : continuous_multilinear_map R M₁ M₂) =>
        mk (multilinear_map.mk (multilinear_map.to_fun (to_multilinear_map f + to_multilinear_map f')) sorry sorry)
          sorry }

@[simp] theorem add_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (f' : continuous_multilinear_map R M₁ M₂) [has_continuous_add M₂] (m : (i : ι) → M₁ i) : coe_fn (f + f') m = coe_fn f m + coe_fn f' m :=
  rfl

@[simp] theorem to_multilinear_map_add {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [has_continuous_add M₂] (f : continuous_multilinear_map R M₁ M₂) (g : continuous_multilinear_map R M₁ M₂) : to_multilinear_map (f + g) = to_multilinear_map f + to_multilinear_map g :=
  rfl

protected instance add_comm_monoid {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [has_continuous_add M₂] : add_comm_monoid (continuous_multilinear_map R M₁ M₂) :=
  add_comm_monoid.mk Add.add sorry 0 sorry sorry sorry

@[simp] theorem sum_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [has_continuous_add M₂] {α : Type u_1} (f : α → continuous_multilinear_map R M₁ M₂) (m : (i : ι) → M₁ i) {s : finset α} : coe_fn (finset.sum s fun (a : α) => f a) m = finset.sum s fun (a : α) => coe_fn (f a) m := sorry

/-- If `f` is a continuous multilinear map, then `f.to_continuous_linear_map m i` is the continuous
linear map obtained by fixing all coordinates but `i` equal to those of `m`, and varying the
`i`-th coordinate. -/
def to_continuous_linear_map {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (m : (i : ι) → M₁ i) (i : ι) : continuous_linear_map R (M₁ i) M₂ :=
  continuous_linear_map.mk
    (linear_map.mk (linear_map.to_fun (multilinear_map.to_linear_map (to_multilinear_map f) m i)) sorry sorry)

/-- The cartesian product of two continuous multilinear maps, as a continuous multilinear map. -/
def prod {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} {M₃ : Type w₃} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [add_comm_monoid M₃] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [semimodule R M₃] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_space M₃] (f : continuous_multilinear_map R M₁ M₂) (g : continuous_multilinear_map R M₁ M₃) : continuous_multilinear_map R M₁ (M₂ × M₃) :=
  mk
    (multilinear_map.mk (multilinear_map.to_fun (multilinear_map.prod (to_multilinear_map f) (to_multilinear_map g)))
      sorry sorry)
    sorry

@[simp] theorem prod_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} {M₃ : Type w₃} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [add_comm_monoid M₃] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [semimodule R M₃] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_space M₃] (f : continuous_multilinear_map R M₁ M₂) (g : continuous_multilinear_map R M₁ M₃) (m : (i : ι) → M₁ i) : coe_fn (prod f g) m = (coe_fn f m, coe_fn g m) :=
  rfl

/-- If `g` is continuous multilinear and `f` is a collection of continuous linear maps,
then `g (f₁ m₁, ..., fₙ mₙ)` is again a continuous multilinear map, that we call
`g.comp_continuous_linear_map f`. -/
def comp_continuous_linear_map {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₁' : ι → Type w₁'} {M₄ : Type w₄} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [(i : ι) → add_comm_monoid (M₁' i)] [add_comm_monoid M₄] [(i : ι) → semimodule R (M₁ i)] [(i : ι) → semimodule R (M₁' i)] [semimodule R M₄] [(i : ι) → topological_space (M₁ i)] [(i : ι) → topological_space (M₁' i)] [topological_space M₄] (g : continuous_multilinear_map R M₁' M₄) (f : (i : ι) → continuous_linear_map R (M₁ i) (M₁' i)) : continuous_multilinear_map R M₁ M₄ :=
  mk
    (multilinear_map.mk
      (multilinear_map.to_fun
        (multilinear_map.comp_linear_map (to_multilinear_map g) fun (i : ι) => continuous_linear_map.to_linear_map (f i)))
      sorry sorry)
    sorry

@[simp] theorem comp_continuous_linear_map_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₁' : ι → Type w₁'} {M₄ : Type w₄} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [(i : ι) → add_comm_monoid (M₁' i)] [add_comm_monoid M₄] [(i : ι) → semimodule R (M₁ i)] [(i : ι) → semimodule R (M₁' i)] [semimodule R M₄] [(i : ι) → topological_space (M₁ i)] [(i : ι) → topological_space (M₁' i)] [topological_space M₄] (g : continuous_multilinear_map R M₁' M₄) (f : (i : ι) → continuous_linear_map R (M₁ i) (M₁' i)) (m : (i : ι) → M₁ i) : coe_fn (comp_continuous_linear_map g f) m = coe_fn g fun (i : ι) => coe_fn (f i) (m i) :=
  rfl

/-- In the specific case of continuous multilinear maps on spaces indexed by `fin (n+1)`, where one
can build an element of `Π(i : fin (n+1)), M i` using `cons`, one can express directly the
additivity of a multilinear map along the first variable. -/
theorem cons_add {R : Type u} {n : ℕ} {M : fin (Nat.succ n) → Type w} {M₂ : Type w₂} [semiring R] [(i : fin (Nat.succ n)) → add_comm_monoid (M i)] [add_comm_monoid M₂] [(i : fin (Nat.succ n)) → semimodule R (M i)] [semimodule R M₂] [(i : fin (Nat.succ n)) → topological_space (M i)] [topological_space M₂] (f : continuous_multilinear_map R M M₂) (m : (i : fin n) → M (fin.succ i)) (x : M 0) (y : M 0) : coe_fn f (fin.cons (x + y) m) = coe_fn f (fin.cons x m) + coe_fn f (fin.cons y m) :=
  multilinear_map.cons_add (to_multilinear_map f) m x y

/-- In the specific case of continuous multilinear maps on spaces indexed by `fin (n+1)`, where one
can build an element of `Π(i : fin (n+1)), M i` using `cons`, one can express directly the
multiplicativity of a multilinear map along the first variable. -/
theorem cons_smul {R : Type u} {n : ℕ} {M : fin (Nat.succ n) → Type w} {M₂ : Type w₂} [semiring R] [(i : fin (Nat.succ n)) → add_comm_monoid (M i)] [add_comm_monoid M₂] [(i : fin (Nat.succ n)) → semimodule R (M i)] [semimodule R M₂] [(i : fin (Nat.succ n)) → topological_space (M i)] [topological_space M₂] (f : continuous_multilinear_map R M M₂) (m : (i : fin n) → M (fin.succ i)) (c : R) (x : M 0) : coe_fn f (fin.cons (c • x) m) = c • coe_fn f (fin.cons x m) :=
  multilinear_map.cons_smul (to_multilinear_map f) m c x

theorem map_piecewise_add {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (m : (i : ι) → M₁ i) (m' : (i : ι) → M₁ i) (t : finset ι) : coe_fn f (finset.piecewise t (m + m') m') =
  finset.sum (finset.powerset t) fun (s : finset ι) => coe_fn f (finset.piecewise s m m') :=
  multilinear_map.map_piecewise_add (to_multilinear_map f) m m' t

/-- Additivity of a continuous multilinear map along all coordinates at the same time,
writing `f (m + m')` as the sum  of `f (s.piecewise m m')` over all sets `s`. -/
theorem map_add_univ {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) [fintype ι] (m : (i : ι) → M₁ i) (m' : (i : ι) → M₁ i) : coe_fn f (m + m') = finset.sum finset.univ fun (s : finset ι) => coe_fn f (finset.piecewise s m m') :=
  multilinear_map.map_add_univ (to_multilinear_map f) m m'

/-- If `f` is continuous multilinear, then `f (Σ_{j₁ ∈ A₁} g₁ j₁, ..., Σ_{jₙ ∈ Aₙ} gₙ jₙ)` is the sum
of `f (g₁ (r 1), ..., gₙ (r n))` where `r` ranges over all functions with `r 1 ∈ A₁`, ...,
`r n ∈ Aₙ`. This follows from multilinearity by expanding successively with respect to each
coordinate. -/
theorem map_sum_finset {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) {α : ι → Type u_1} [fintype ι] (g : (i : ι) → α i → M₁ i) (A : (i : ι) → finset (α i)) : (coe_fn f fun (i : ι) => finset.sum (A i) fun (j : α i) => g i j) =
  finset.sum (fintype.pi_finset A) fun (r : (a : ι) → α a) => coe_fn f fun (i : ι) => g i (r i) :=
  multilinear_map.map_sum_finset (to_multilinear_map f) (fun (i : ι) (j : α i) => g i j) fun (i : ι) => A i

/-- If `f` is continuous multilinear, then `f (Σ_{j₁} g₁ j₁, ..., Σ_{jₙ} gₙ jₙ)` is the sum of
`f (g₁ (r 1), ..., gₙ (r n))` where `r` ranges over all functions `r`. This follows from
multilinearity by expanding successively with respect to each coordinate. -/
theorem map_sum {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) {α : ι → Type u_1} [fintype ι] (g : (i : ι) → α i → M₁ i) [(i : ι) → fintype (α i)] : (coe_fn f fun (i : ι) => finset.sum finset.univ fun (j : α i) => g i j) =
  finset.sum finset.univ fun (r : (i : ι) → α i) => coe_fn f fun (i : ι) => g i (r i) :=
  multilinear_map.map_sum (to_multilinear_map f) fun (i : ι) (j : α i) => g i j

/-- Reinterpret an `A`-multilinear map as an `R`-multilinear map, if `A` is an algebra over `R`
and their actions on all involved semimodules agree with the action of `R` on `A`. -/
def restrict_scalars (R : Type u) {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {A : Type u_1} [semiring A] [has_scalar R A] [(i : ι) → semimodule A (M₁ i)] [semimodule A M₂] [∀ (i : ι), is_scalar_tower R A (M₁ i)] [is_scalar_tower R A M₂] (f : continuous_multilinear_map A M₁ M₂) : continuous_multilinear_map R M₁ M₂ :=
  mk (multilinear_map.restrict_scalars R (to_multilinear_map f)) sorry

@[simp] theorem coe_restrict_scalars (R : Type u) {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {A : Type u_1} [semiring A] [has_scalar R A] [(i : ι) → semimodule A (M₁ i)] [semimodule A M₂] [∀ (i : ι), is_scalar_tower R A (M₁ i)] [is_scalar_tower R A M₂] (f : continuous_multilinear_map A M₁ M₂) : ⇑(restrict_scalars R f) = ⇑f :=
  rfl

@[simp] theorem map_sub {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (m : (i : ι) → M₁ i) (i : ι) (x : M₁ i) (y : M₁ i) : coe_fn f (function.update m i (x - y)) = coe_fn f (function.update m i x) - coe_fn f (function.update m i y) :=
  multilinear_map.map_sub (to_multilinear_map f) m i x y

protected instance has_neg {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_add_group M₂] : Neg (continuous_multilinear_map R M₁ M₂) :=
  { neg :=
      fun (f : continuous_multilinear_map R M₁ M₂) =>
        mk (multilinear_map.mk (multilinear_map.to_fun (-to_multilinear_map f)) sorry sorry) sorry }

@[simp] theorem neg_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) [topological_add_group M₂] (m : (i : ι) → M₁ i) : coe_fn (-f) m = -coe_fn f m :=
  rfl

protected instance has_sub {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_add_group M₂] : Sub (continuous_multilinear_map R M₁ M₂) :=
  { sub :=
      fun (f g : continuous_multilinear_map R M₁ M₂) =>
        mk (multilinear_map.mk (multilinear_map.to_fun (to_multilinear_map f - to_multilinear_map g)) sorry sorry) sorry }

@[simp] theorem sub_apply {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (f' : continuous_multilinear_map R M₁ M₂) [topological_add_group M₂] (m : (i : ι) → M₁ i) : coe_fn (f - f') m = coe_fn f m - coe_fn f' m :=
  rfl

protected instance add_comm_group {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_add_group M₂] : add_comm_group (continuous_multilinear_map R M₁ M₂) :=
  add_comm_group.mk Add.add sorry 0 sorry sorry Neg.neg Sub.sub sorry sorry

theorem map_piecewise_smul {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [comm_semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) (c : ι → R) (m : (i : ι) → M₁ i) (s : finset ι) : coe_fn f (finset.piecewise s (fun (i : ι) => c i • m i) m) = (finset.prod s fun (i : ι) => c i) • coe_fn f m :=
  multilinear_map.map_piecewise_smul (to_multilinear_map f) (fun (i : ι) => c i) (fun (i : ι) => m i) s

/-- Multiplicativity of a continuous multilinear map along all coordinates at the same time,
writing `f (λ i, c i • m i)` as `(∏ i, c i) • f m`. -/
theorem map_smul_univ {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [comm_semiring R] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → semimodule R (M₁ i)] [semimodule R M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] (f : continuous_multilinear_map R M₁ M₂) [fintype ι] (c : ι → R) (m : (i : ι) → M₁ i) : (coe_fn f fun (i : ι) => c i • m i) = (finset.prod finset.univ fun (i : ι) => c i) • coe_fn f m :=
  multilinear_map.map_smul_univ (to_multilinear_map f) (fun (i : ι) => c i) fun (i : ι) => m i

protected instance has_scalar {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {R' : Type u_1} {A : Type u_2} [comm_semiring R'] [semiring A] [algebra R' A] [(i : ι) → semimodule A (M₁ i)] [semimodule R' M₂] [semimodule A M₂] [is_scalar_tower R' A M₂] [topological_space R'] [topological_semimodule R' M₂] : has_scalar R' (continuous_multilinear_map A M₁ M₂) :=
  has_scalar.mk
    fun (c : R') (f : continuous_multilinear_map A M₁ M₂) =>
      mk (multilinear_map.mk (multilinear_map.to_fun (c • to_multilinear_map f)) sorry sorry) sorry

@[simp] theorem smul_apply {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {R' : Type u_1} {A : Type u_2} [comm_semiring R'] [semiring A] [algebra R' A] [(i : ι) → semimodule A (M₁ i)] [semimodule R' M₂] [semimodule A M₂] [is_scalar_tower R' A M₂] [topological_space R'] [topological_semimodule R' M₂] (f : continuous_multilinear_map A M₁ M₂) (c : R') (m : (i : ι) → M₁ i) : coe_fn (c • f) m = c • coe_fn f m :=
  rfl

@[simp] theorem to_multilinear_map_smul {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {R' : Type u_1} {A : Type u_2} [comm_semiring R'] [semiring A] [algebra R' A] [(i : ι) → semimodule A (M₁ i)] [semimodule R' M₂] [semimodule A M₂] [is_scalar_tower R' A M₂] [topological_space R'] [topological_semimodule R' M₂] (c : R') (f : continuous_multilinear_map A M₁ M₂) : to_multilinear_map (c • f) = c • to_multilinear_map f :=
  rfl

protected instance is_scalar_tower {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {R' : Type u_1} {A : Type u_2} [comm_semiring R'] [semiring A] [algebra R' A] [(i : ι) → semimodule A (M₁ i)] [semimodule R' M₂] [semimodule A M₂] [is_scalar_tower R' A M₂] [topological_space R'] [topological_semimodule R' M₂] {R'' : Type u_3} [comm_semiring R''] [has_scalar R' R''] [algebra R'' A] [semimodule R'' M₂] [is_scalar_tower R'' A M₂] [is_scalar_tower R' R'' M₂] [topological_space R''] [topological_semimodule R'' M₂] : is_scalar_tower R' R'' (continuous_multilinear_map A M₁ M₂) :=
  is_scalar_tower.mk
    fun (c₁ : R') (c₂ : R'') (f : continuous_multilinear_map A M₁ M₂) =>
      ext fun (x : (i : ι) → M₁ i) => smul_assoc c₁ c₂ (coe_fn (to_multilinear_map f) x)

/-- The space of continuous multilinear maps over an algebra over `R` is a module over `R`, for the
pointwise addition and scalar multiplication. -/
protected instance semimodule {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {R' : Type u_1} {A : Type u_2} [comm_semiring R'] [semiring A] [algebra R' A] [(i : ι) → semimodule A (M₁ i)] [semimodule R' M₂] [semimodule A M₂] [is_scalar_tower R' A M₂] [topological_space R'] [topological_semimodule R' M₂] [has_continuous_add M₂] : semimodule R' (continuous_multilinear_map A M₁ M₂) :=
  semimodule.mk sorry sorry

/-- Linear map version of the map `to_multilinear_map` associating to a continuous multilinear map
the corresponding multilinear map. -/
@[simp] theorem to_multilinear_map_linear_apply {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} [DecidableEq ι] [(i : ι) → add_comm_monoid (M₁ i)] [add_comm_monoid M₂] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] {R' : Type u_1} {A : Type u_2} [comm_semiring R'] [semiring A] [algebra R' A] [(i : ι) → semimodule A (M₁ i)] [semimodule R' M₂] [semimodule A M₂] [is_scalar_tower R' A M₂] [topological_space R'] [topological_semimodule R' M₂] [has_continuous_add M₂] (f : continuous_multilinear_map A M₁ M₂) : coe_fn to_multilinear_map_linear f = to_multilinear_map f :=
  Eq.refl (coe_fn to_multilinear_map_linear f)

end continuous_multilinear_map

namespace continuous_linear_map

/-- Composing a continuous multilinear map with a continuous linear map gives again a
continuous multilinear map. -/
def comp_continuous_multilinear_map {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} {M₃ : Type w₃} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [add_comm_group M₃] [(i : ι) → module R (M₁ i)] [module R M₂] [module R M₃] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_space M₃] (g : continuous_linear_map R M₂ M₃) (f : continuous_multilinear_map R M₁ M₂) : continuous_multilinear_map R M₁ M₃ :=
  continuous_multilinear_map.mk
    (multilinear_map.mk
      (multilinear_map.to_fun
        (linear_map.comp_multilinear_map (to_linear_map g) (continuous_multilinear_map.to_multilinear_map f)))
      sorry sorry)
    sorry

@[simp] theorem comp_continuous_multilinear_map_coe {R : Type u} {ι : Type v} {M₁ : ι → Type w₁} {M₂ : Type w₂} {M₃ : Type w₃} [DecidableEq ι] [ring R] [(i : ι) → add_comm_group (M₁ i)] [add_comm_group M₂] [add_comm_group M₃] [(i : ι) → module R (M₁ i)] [module R M₂] [module R M₃] [(i : ι) → topological_space (M₁ i)] [topological_space M₂] [topological_space M₃] (g : continuous_linear_map R M₂ M₃) (f : continuous_multilinear_map R M₁ M₂) : ⇑(comp_continuous_multilinear_map g f) = ⇑g ∘ ⇑f :=
  funext fun (m : (i : ι) → M₁ i) => Eq.refl (coe_fn (comp_continuous_multilinear_map g f) m)


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

! This file was ported from Lean 3 source module ring_theory.witt_vector.teichmuller
! leanprover-community/mathlib commit c0a51cf2de54089d69301befc4c73bbc2f5c7342
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.RingTheory.WittVector.Basic

/-!
# Teichmüller lifts

This file defines `witt_vector.teichmuller`, a monoid hom `R →* 𝕎 R`, which embeds `r : R` as the
`0`-th component of a Witt vector whose other coefficients are `0`.

## Main declarations

- `witt_vector.teichmuller`: the Teichmuller map.
- `witt_vector.map_teichmuller`: `witt_vector.teichmuller` is a natural transformation.
- `witt_vector.ghost_component_teichmuller`:
  the `n`-th ghost component of `witt_vector.teichmuller p r` is `r ^ p ^ n`.

## References

* [Hazewinkel, *Witt Vectors*][Haze09]

* [Commelin and Lewis, *Formalizing the Ring of Witt Vectors*][CL21]
-/

namespace WittVector

open MvPolynomial

variable (p : ℕ) {R S : Type _} [hp : Fact p.Prime] [CommRing R] [CommRing S]

-- mathport name: expr𝕎
local notation "𝕎" => WittVector p

-- type as `\bbW`
/-- The underlying function of the monoid hom `witt_vector.teichmuller`.
The `0`-th coefficient of `teichmuller_fun p r` is `r`, and all others are `0`.
-/
def teichmullerFun (r : R) : 𝕎 R :=
  ⟨p, fun n => if n = 0 then r else 0⟩
#align witt_vector.teichmuller_fun WittVector.teichmullerFun

/-!
## `teichmuller` is a monoid homomorphism

On ghost components, it is clear that `teichmuller_fun` is a monoid homomorphism.
But in general the ghost map is not injective.
We follow the same strategy as for proving that the ring operations on `𝕎 R`
satisfy the ring axioms.

1. We first prove it for rings `R` where `p` is invertible,
   because then the ghost map is in fact an isomorphism.
2. After that, we derive the result for `mv_polynomial R ℤ`,
3. and from that we can prove the result for arbitrary `R`.
-/

include hp

private theorem ghost_component_teichmuller_fun (r : R) (n : ℕ) :
    ghostComponent n (teichmullerFun p r) = r ^ p ^ n :=
  by
  rw [ghost_component_apply, aeval_wittPolynomial, Finset.sum_eq_single 0, pow_zero, one_mul,
    tsub_zero]
  · rfl
  · intro i hi h0
    convert MulZeroClass.mul_zero _
    convert zero_pow _
    · cases i
      · contradiction
      · rfl
    · exact pow_pos hp.1.Pos _
  · rw [Finset.mem_range]
    intro h
    exact (h (Nat.succ_pos n)).elim
#align witt_vector.ghost_component_teichmuller_fun witt_vector.ghost_component_teichmuller_fun

private theorem map_teichmuller_fun (f : R →+* S) (r : R) :
    map f (teichmullerFun p r) = teichmullerFun p (f r) :=
  by
  ext n
  cases n
  · rfl
  · exact f.map_zero
#align witt_vector.map_teichmuller_fun witt_vector.map_teichmuller_fun

private theorem teichmuller_mul_aux₁ (x y : MvPolynomial R ℚ) :
    teichmullerFun p (x * y) = teichmullerFun p x * teichmullerFun p y :=
  by
  apply (ghost_map.bijective_of_invertible p (MvPolynomial R ℚ)).1
  rw [RingHom.map_mul]
  ext1 n
  simp only [Pi.mul_apply, ghost_map_apply, ghost_component_teichmuller_fun, mul_pow]
#align witt_vector.teichmuller_mul_aux₁ witt_vector.teichmuller_mul_aux₁

private theorem teichmuller_mul_aux₂ (x y : MvPolynomial R ℤ) :
    teichmullerFun p (x * y) = teichmullerFun p x * teichmullerFun p y :=
  by
  refine'
    map_injective (MvPolynomial.map (Int.castRingHom ℚ))
      (MvPolynomial.map_injective _ Int.cast_injective) _
  simp only [teichmuller_mul_aux₁, map_teichmuller_fun, RingHom.map_mul]
#align witt_vector.teichmuller_mul_aux₂ witt_vector.teichmuller_mul_aux₂

/-- The Teichmüller lift of an element of `R` to `𝕎 R`.
The `0`-th coefficient of `teichmuller p r` is `r`, and all others are `0`.
This is a monoid homomorphism. -/
def teichmuller : R →* 𝕎 R where
  toFun := teichmullerFun p
  map_one' := by
    ext ⟨⟩
    · rw [one_coeff_zero]
      rfl
    · rw [one_coeff_eq_of_pos _ _ _ (Nat.succ_pos n)]
      rfl
  map_mul' := by
    intro x y
    rcases counit_surjective R x with ⟨x, rfl⟩
    rcases counit_surjective R y with ⟨y, rfl⟩
    simp only [← map_teichmuller_fun, ← RingHom.map_mul, teichmuller_mul_aux₂]
#align witt_vector.teichmuller WittVector.teichmuller

@[simp]
theorem teichmuller_coeff_zero (r : R) : (teichmuller p r).coeff 0 = r :=
  rfl
#align witt_vector.teichmuller_coeff_zero WittVector.teichmuller_coeff_zero

@[simp]
theorem teichmuller_coeff_pos (r : R) : ∀ (n : ℕ) (hn : 0 < n), (teichmuller p r).coeff n = 0
  | n + 1, _ => rfl
#align witt_vector.teichmuller_coeff_pos WittVector.teichmuller_coeff_pos

@[simp]
theorem teichmuller_zero : teichmuller p (0 : R) = 0 := by
  ext ⟨⟩ <;>
    · rw [zero_coeff]
      rfl
#align witt_vector.teichmuller_zero WittVector.teichmuller_zero

/-- `teichmuller` is a natural transformation. -/
@[simp]
theorem map_teichmuller (f : R →+* S) (r : R) : map f (teichmuller p r) = teichmuller p (f r) :=
  map_teichmullerFun _ _ _
#align witt_vector.map_teichmuller WittVector.map_teichmuller

/-- The `n`-th ghost component of `teichmuller p r` is `r ^ p ^ n`. -/
@[simp]
theorem ghostComponent_teichmuller (r : R) (n : ℕ) :
    ghostComponent n (teichmuller p r) = r ^ p ^ n :=
  ghostComponent_teichmullerFun _ _ _
#align witt_vector.ghost_component_teichmuller WittVector.ghostComponent_teichmuller

end WittVector


/-
Copyright (c) 2021 Yury G. Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Yury G. Kudryashov
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.analysis.analytic.basic
import Mathlib.PostPort

universes u_1 u_2 u_3

namespace Mathlib

/-!
# Linear functions are analytic

In this file we prove that a `continuous_linear_map` defines an analytic function with
the formal power series `f x = f a + f (x - a)`.
-/

namespace continuous_linear_map

/-- Formal power series of a continuous linear map `f : E →L[𝕜] F` at `x : E`:
`f y = f x + f (y - x)`. -/
@[simp] def fpower_series {𝕜 : Type u_1} [nondiscrete_normed_field 𝕜] {E : Type u_2} [normed_group E] [normed_space 𝕜 E] {F : Type u_3} [normed_group F] [normed_space 𝕜 F] (f : continuous_linear_map 𝕜 E F) (x : E) : formal_multilinear_series 𝕜 E F :=
  sorry

@[simp] theorem fpower_series_apply_add_two {𝕜 : Type u_1} [nondiscrete_normed_field 𝕜] {E : Type u_2} [normed_group E] [normed_space 𝕜 E] {F : Type u_3} [normed_group F] [normed_space 𝕜 F] (f : continuous_linear_map 𝕜 E F) (x : E) (n : ℕ) : fpower_series f x (n + bit0 1) = 0 :=
  rfl

@[simp] theorem fpower_series_radius {𝕜 : Type u_1} [nondiscrete_normed_field 𝕜] {E : Type u_2} [normed_group E] [normed_space 𝕜 E] {F : Type u_3} [normed_group F] [normed_space 𝕜 F] (f : continuous_linear_map 𝕜 E F) (x : E) : formal_multilinear_series.radius (fpower_series f x) = ⊤ :=
  formal_multilinear_series.radius_eq_top_of_forall_image_add_eq_zero (fpower_series f x) (bit0 1) fun (n : ℕ) => rfl

protected theorem has_fpower_series_on_ball {𝕜 : Type u_1} [nondiscrete_normed_field 𝕜] {E : Type u_2} [normed_group E] [normed_space 𝕜 E] {F : Type u_3} [normed_group F] [normed_space 𝕜 F] (f : continuous_linear_map 𝕜 E F) (x : E) : has_fpower_series_on_ball (⇑f) (fpower_series f x) x ⊤ := sorry

protected theorem has_fpower_series_at {𝕜 : Type u_1} [nondiscrete_normed_field 𝕜] {E : Type u_2} [normed_group E] [normed_space 𝕜 E] {F : Type u_3} [normed_group F] [normed_space 𝕜 F] (f : continuous_linear_map 𝕜 E F) (x : E) : has_fpower_series_at (⇑f) (fpower_series f x) x :=
  Exists.intro ⊤ (continuous_linear_map.has_fpower_series_on_ball f x)

protected theorem analytic_at {𝕜 : Type u_1} [nondiscrete_normed_field 𝕜] {E : Type u_2} [normed_group E] [normed_space 𝕜 E] {F : Type u_3} [normed_group F] [normed_space 𝕜 F] (f : continuous_linear_map 𝕜 E F) (x : E) : analytic_at 𝕜 (⇑f) x :=
  has_fpower_series_at.analytic_at (continuous_linear_map.has_fpower_series_at f x)


import data.set.basic
import data.quot
import ring_theory.ideal.operations
import ring_theory.ideal.quotient
import linear_algebra.quotient

variables (R M : Type _) [comm_ring R] [add_comm_group M] [module R M] (I : ideal R)

/- CURRENT GOAL:
variables [is_noetherian_ring R] [local_ring R]
def m := local_ring.maximal_ideal R
def regular_ring : Prop :=
  module.rank (R ⧸ m) (m ⧸ (m • (⊤ submodule R m))) = μ(m)

but for this need
  (m /m²) to be an R⧸M module
  μ(m) to be defined
-/

instance quotient_over_ideal_smul_residue : has_smul (R ⧸ I) (M ⧸ (I • (⊤ : submodule R M))) :=
⟨ λ r m, @quotient.lift_on₂' _ _ _ (submodule.quotient_rel _) (submodule.quotient_rel _) r m
    (λ (r : R) (m : M), submodule.quotient.mk $ r • m)
  begin
    intros r₁ m₁ r₂ m₂ h₁ h₂,
    unfold,
    rw submodule.quotient.eq,
    have : (r₁ = r₂ + (r₁ - r₂)) := by ring,
    rw this, clear this,
    have : (r₂ + (r₁ - r₂))•m₁ = r₂•m₁ + (r₁ - r₂)•m₁,
    { rw add_smul },
    rw this, clear this,
    have silly_lemma : ∀(a b c : M), a + b - c = (a - c) + b,
    {
      introv,
      repeat { rw add_comm_group.sub_eq_add_neg, },
      rw add_comm_group.add_assoc,
      have : (b + -c) = (-c + b) := add_comm_group.add_comm _ _,
      erw this, clear this,
      rw ← add_comm_group.add_assoc,
      refl
    },
    rw silly_lemma,
    apply (submodule.add_mem (I • (⊤ : submodule R M))),
    {
      have : m₁ = m₂ + (m₁ - m₂),
      {
        simp only [add_sub_cancel'_right, eq_self_iff_true]
      },
      rw [this, smul_add, silly_lemma, add_comm_group.sub_eq_add_neg, add_neg_self, zero_add ],
      clear this,
      apply (submodule.smul_mem' _ _ _),
      rw submodule.quotient_rel_r_def at h₂,
      assumption
    },
    {
      apply submodule.smul_mem_smul,
      {
        rw ← quotient.eq' at h₁,
        rw ← ideal.quotient.eq,
        assumption,
      },
      {
        exact submodule.mem_top,
      },
    },
  end⟩

/-
def quotient_over_ideal_residue_module : module (R ⧸ I) (M ⧸ (I • (⊤ : submodule R M))) :=
{
  one_smul  := sorry,
  mul_smul  := sorry,
  smul_add  := sorry,
  smul_zero := sorry,
  zero_smul := sorry,
  add_smul  := sorry,
}
-/


/-
Copyright (c) 2022 Moritz Doll. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Moritz Doll
-/
import topology.algebra.module.weak_dual
import analysis.normed.normed_field
import analysis.locally_convex.with_seminorms

/-!
# Weak Dual in Topological Vector Spaces

We prove that the weak topology induced by a bilinear form `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜` is locally
convex and we explicit give a neighborhood basis in terms of the family of seminorms `λ x, ∥B x y∥`
for `y : F`.

## Main definitions

* `linear_map.to_seminorm`: turn a linear form `f : E →ₗ[𝕜] 𝕜` into a seminorm `λ x, ∥f x∥`.
* `linear_map.to_seminorm_family`: turn a bilinear form `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜` into a map
`F → seminorm 𝕜 E`.

## Main statements

* `linear_map.has_basis_weak_bilin`: the seminorm balls of `B.to_seminorm_family` form a
neighborhood basis of `0` in the weak topology.
* `linear_map.to_seminorm_family.with_seminorms`: the topology of a weak space is induced by the
family of seminorm `B.to_seminorm_family`.
* `weak_bilin.locally_convex_space`: a spaced endowed with a weak topology is locally convex.

## References

* [Bourbaki, *Topological Vector Spaces*][bourbaki1987]

## Tags

weak dual, seminorm
-/

variables {𝕜 E F ι : Type*}

open_locale topological_space

section bilin_form

namespace linear_map

variables [normed_field 𝕜] [add_comm_group E] [module 𝕜 E] [add_comm_group F] [module 𝕜 F]

/-- Construct a seminorm from a linear form `f : E →ₗ[𝕜] 𝕜` over a normed field `𝕜` by
`λ x, ∥f x∥` -/
def to_seminorm (f : E →ₗ[𝕜] 𝕜) : seminorm 𝕜 E :=
{ to_fun := λ x, ∥f x∥,
  smul' := λ a x, by simp only [map_smulₛₗ, ring_hom.id_apply, smul_eq_mul, norm_mul],
  triangle' := λ x x', by { simp only [map_add, add_apply], exact norm_add_le _ _ } }

lemma coe_to_seminorm {f : E →ₗ[𝕜] 𝕜} :
  ⇑f.to_seminorm = λ x, ∥f x∥ := rfl

@[simp] lemma to_seminorm_apply {f : E →ₗ[𝕜] 𝕜} {x : E} :
  f.to_seminorm x = ∥f x∥ := rfl

lemma to_seminorm_ball_zero {f : E →ₗ[𝕜] 𝕜} {r : ℝ} :
  seminorm.ball f.to_seminorm 0 r = { x : E | ∥f x∥ < r} :=
by simp only [seminorm.ball_zero_eq, to_seminorm_apply]

lemma to_seminorm_comp (f : F →ₗ[𝕜] 𝕜) (g : E →ₗ[𝕜] F) :
  f.to_seminorm.comp g = (f.comp g).to_seminorm :=
by { ext, simp only [seminorm.comp_apply, to_seminorm_apply, coe_comp] }

/-- Construct a family of seminorms from a bilinear form. -/
def to_seminorm_family (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : seminorm_family 𝕜 E F :=
λ y, (B.flip y).to_seminorm

@[simp] lemma to_seminorm_family_apply {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜} {x y} :
  (B.to_seminorm_family y) x = ∥B x y∥ := rfl

end linear_map

end bilin_form

section topology

variables [normed_field 𝕜] [add_comm_group E] [module 𝕜 E] [add_comm_group F] [module 𝕜 F]
variables [nonempty ι]
variables {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜}

lemma linear_map.has_basis_weak_bilin (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) :
  (𝓝 (0 : weak_bilin B)).has_basis B.to_seminorm_family.basis_sets id :=
begin
  let p := B.to_seminorm_family,
  rw [nhds_induced, nhds_pi],
  simp only [map_zero, linear_map.zero_apply],
  have h := @metric.nhds_basis_ball 𝕜 _ 0,
  have h' := filter.has_basis_pi (λ (i : F), h),
  have h'' := filter.has_basis.comap (λ x y, B x y) h',
  refine h''.to_has_basis _ _,
  { rintros (U : set F × (F → ℝ)) hU,
    cases hU with hU₁ hU₂,
    simp only [id.def],
    let U' := hU₁.to_finset,
    by_cases hU₃ : U.fst.nonempty,
    { have hU₃' : U'.nonempty := (set.finite.to_finset.nonempty hU₁).mpr hU₃,
      let r := U'.inf' hU₃' U.snd,
      have hr : 0 < r :=
      (finset.lt_inf'_iff hU₃' _).mpr (λ y hy, hU₂ y ((set.finite.mem_to_finset hU₁).mp hy)),
      use [seminorm.ball (U'.sup p) (0 : E) r],
      refine ⟨p.basis_sets_mem _ hr, λ x hx y hy, _⟩,
      simp only [set.mem_preimage, set.mem_pi, mem_ball_zero_iff],
      rw seminorm.mem_ball_zero at hx,
      rw ←linear_map.to_seminorm_family_apply,
      have hyU' : y ∈ U' := (set.finite.mem_to_finset hU₁).mpr hy,
      have hp : p y ≤ U'.sup p := finset.le_sup hyU',
      refine lt_of_le_of_lt (hp x) (lt_of_lt_of_le hx _),
      exact finset.inf'_le _ hyU' },
    rw set.not_nonempty_iff_eq_empty.mp hU₃,
    simp only [set.empty_pi, set.preimage_univ, set.subset_univ, and_true],
    exact Exists.intro ((p 0).ball 0 1) (p.basis_sets_singleton_mem 0 one_pos) },
  rintros U (hU : U ∈ p.basis_sets),
  rw seminorm_family.basis_sets_iff at hU,
  rcases hU with ⟨s, r, hr, hU⟩,
  rw hU,
  refine ⟨(s, λ _, r), ⟨by simp only [s.finite_to_set], λ y hy, hr⟩, λ x hx, _⟩,
  simp only [set.mem_preimage, set.mem_pi, finset.mem_coe, mem_ball_zero_iff] at hx,
  simp only [id.def, seminorm.mem_ball, sub_zero],
  refine seminorm.finset_sup_apply_lt hr (λ y hy, _),
  rw linear_map.to_seminorm_family_apply,
  exact hx y hy,
end

instance : with_seminorms
  (linear_map.to_seminorm_family B : F → seminorm 𝕜 (weak_bilin B)) :=
seminorm_family.with_seminorms_of_has_basis _ B.has_basis_weak_bilin

end topology

section locally_convex

variables [normed_field 𝕜] [add_comm_group E] [module 𝕜 E] [add_comm_group F] [module 𝕜 F]
variables [nonempty ι] [normed_space ℝ 𝕜] [module ℝ E] [is_scalar_tower ℝ 𝕜 E]

instance {B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜} : locally_convex_space ℝ (weak_bilin B) :=
seminorm_family.to_locally_convex_space B.to_seminorm_family

end locally_convex


example (p q r : Prop) : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) := by
  apply Iff.intro
  . intro h
    apply Or.elim (And.right h)
    . intro hq
      apply Or.inl
      apply And.intro
      . exact And.left h
      . exact hq
    . intro hr
      apply Or.inr
      apply And.intro
      . exact And.left h
      . exact hr
  . intro h
    apply Or.elim h
    . intro hpq
      apply And.intro
      . exact And.left hpq
      . apply Or.inl
        exact And.right hpq
    . intro hpr
      apply And.intro
      . exact And.left hpr
      . apply Or.inr
        exact And.right hpr