import connected

noncomputable theory

variables {V : Type*} {G : quiver V} [inhabited V]

local notation `root` := default V

def quiver.path.length {a} : Π {b : V} (p : quiver.path G a b), ℕ
| _  quiver.path.nil       := 0
| _ (quiver.path.cons p _) := p.length + 1

variables [directed_connected G] (G)

/-- A path to `root` of minimal length. -/
def shortest_path (a : V) : G.path root a :=
well_founded.min (measure_wf $ λ p : G.path root a, p.length) set.univ set.univ_nonempty

/-- The length of a path is at least the length of the shortest path -/
lemma shortest_path_spec {a : V} (p : G.path root a) :
  (shortest_path G a).length ≤ p.length :=
begin
  have : ¬ (p.length < (shortest_path G a).length) :=
    well_founded.not_lt_min (measure_wf _) set.univ _ trivial,
  simpa using this,
end

/-- The geodesic subgraph. For each non-root vertex, there is an edge from a parent:
    some vertex that is closer to `root`. -/
def geodesic_subgraph : subquiver G :=
λ a b e, ∃ p : G.path root a, shortest_path G b = quiver.path.cons p e

-- todo: write this idiomatically
lemma paths_are_unique : ∀ {s : V} {p q : (¡geodesic_subgraph G).path root s}, p = q
| _ (quiver.path.nil) := begin
  rintro ( _ | _ ),
  { refl },
  exfalso,
  rcases q_ᾰ_1 with ⟨_, _, h⟩,
  have : (shortest_path G root).length ≤ 0 :=
    shortest_path_spec G quiver.path.nil,
  rw h at this,
  change _ + 1 ≤ 0 at this,
  simpa only [nonpos_iff_eq_zero] using this,
end
| t (quiver.path.cons p e) := begin
  rcases e with ⟨_, _, h⟩,
  rintro ( _ | _ ),
  { have : (shortest_path G root).length ≤ 0 :=
      shortest_path_spec G quiver.path.nil,
    rw h at this,
    change _ + 1 ≤ 0 at this,
    simpa only [nonpos_iff_eq_zero] using this },
  { rcases q_ᾰ_1 with ⟨_, _, hq⟩,
    rw h at hq,
    cases hq,
    congr,
    apply paths_are_unique }
end

def geodesic_path : Π (gas : ℕ) (t : V), (shortest_path G t).length ≤ gas →
      (¡geodesic_subgraph G).path root t :=
begin -- todo: write this idiomatically
  intro gas,
  induction gas with gas ih,
  { intros t h,
    have : ∃ p, p = shortest_path G t,
    { refine ⟨_, rfl⟩ },
    rcases (classical.indefinite_description _ this) with ⟨p, hp⟩,
    cases p with s t p e,
    { exact quiver.path.nil },
    { exfalso, -- out of gas
      rw ←hp at h,
      simpa using h } },
  { intros t h,
    have : ∃ p, p = shortest_path G t,
    { refine ⟨_, rfl⟩ },
    rcases (classical.indefinite_description _ this) with ⟨p, hp⟩,
    cases p with s t p e,
    { exact quiver.path.nil },
    { refine quiver.path.cons _ ⟨e, p, hp.symm⟩,
      apply ih,
      rw ←hp at h,
      change _ + 1 ≤ _ + 1 at h,
      rw add_le_add_iff_right at h,
      exact le_trans (shortest_path_spec G p) h } }
end

instance geodesic_tree : is_arbor ¡geodesic_subgraph G :=
{ unique_path := λ b,
  { default := geodesic_path G _ b (le_refl _),
    uniq := λ _, paths_are_unique G } }


/-
Copyright (c) 2020 David Wärn. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Wärn
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.category_theory.natural_isomorphism
import Mathlib.PostPort

universes v u l u_1 u_2

namespace Mathlib

/-!
# Quotient category

Constructs the quotient of a category by an arbitrary family of relations on its hom-sets,
by introducing a type synonym for the objects, and identifying homs as necessary.

This is analogous to 'the quotient of a group by the normal closure of a subset', rather
than 'the quotient of a group by a normal subgroup'.
-/

namespace category_theory

/-- A type synonom for `C`, thought of as the objects of the quotient category. -/
structure quotient {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) where
  as : C

protected instance quotient.inhabited {C : Type u} [category C]
    (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) [Inhabited C] : Inhabited (quotient r) :=
  { default := quotient.mk Inhabited.default }

namespace quotient

/-- Generates the closure of a family of relations w.r.t. composition from left and right. -/
inductive comp_closure {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {s : C}
    {t : C} : (s ⟶ t) → (s ⟶ t) → Prop
    where
| intro :
    ∀ {a b : C} (f : s ⟶ a) (m₁ m₂ : a ⟶ b) (g : b ⟶ t),
      r m₁ m₂ → comp_closure r (f ≫ m₁ ≫ g) (f ≫ m₂ ≫ g)

theorem comp_left {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {a : C}
    {b : C} {c : C} (f : a ⟶ b) (g₁ : b ⟶ c) (g₂ : b ⟶ c) (h : comp_closure r g₁ g₂) :
    comp_closure r (f ≫ g₁) (f ≫ g₂) :=
  sorry

theorem comp_right {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {a : C}
    {b : C} {c : C} (g : b ⟶ c) (f₁ : a ⟶ b) (f₂ : a ⟶ b) (h : comp_closure r f₁ f₂) :
    comp_closure r (f₁ ≫ g) (f₂ ≫ g) :=
  sorry

/-- Hom-sets of the quotient category. -/
def hom {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) (s : quotient r)
    (t : quotient r) :=
  Quot (comp_closure r)

protected instance hom.inhabited {C : Type u} [category C]
    (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) (a : quotient r) : Inhabited (hom r a a) :=
  { default := Quot.mk (comp_closure r) 𝟙 }

/-- Composition in the quotient category. -/
def comp {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {a : quotient r}
    {b : quotient r} {c : quotient r} : hom r a b → hom r b c → hom r a c :=
  fun (hf : hom r a b) (hg : hom r b c) =>
    quot.lift_on hf
      (fun (f : as a ⟶ as b) =>
        quot.lift_on hg (fun (g : as b ⟶ as c) => Quot.mk (comp_closure r) (f ≫ g)) sorry)
      sorry

@[simp] theorem comp_mk {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop)
    {a : quotient r} {b : quotient r} {c : quotient r} (f : as a ⟶ as b) (g : as b ⟶ as c) :
    comp r (Quot.mk (comp_closure r) f) (Quot.mk (comp_closure r) g) =
        Quot.mk (comp_closure r) (f ≫ g) :=
  rfl

protected instance category {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) :
    category (quotient r) :=
  category.mk

/-- The functor from a category to its quotient. -/
@[simp] theorem functor_map {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop)
    (_x : C) :
    ∀ (_x_1 : C) (f : _x ⟶ _x_1), functor.map (functor r) f = Quot.mk (comp_closure r) f :=
  fun (_x_1 : C) (f : _x ⟶ _x_1) => Eq.refl (functor.map (functor r) f)

protected theorem induction {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop)
    {P : {a b : quotient r} → (a ⟶ b) → Prop}
    (h : ∀ {x y : C} (f : x ⟶ y), P (functor.map (functor r) f)) {a : quotient r} {b : quotient r}
    (f : a ⟶ b) : P f :=
  sorry

protected theorem sound {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {a : C}
    {b : C} {f₁ : a ⟶ b} {f₂ : a ⟶ b} (h : r f₁ f₂) :
    functor.map (functor r) f₁ = functor.map (functor r) f₂ :=
  sorry

/-- The induced functor on the quotient category. -/
def lift {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {D : Type u_1}
    [category D] (F : C ⥤ D)
    (H : ∀ (x y : C) (f₁ f₂ : x ⟶ y), r f₁ f₂ → functor.map F f₁ = functor.map F f₂) :
    quotient r ⥤ D :=
  functor.mk (fun (a : quotient r) => functor.obj F (as a))
    fun (a b : quotient r) (hf : a ⟶ b) =>
      quot.lift_on hf (fun (f : as a ⟶ as b) => functor.map F f) sorry

/-- The original functor factors through the induced functor. -/
def lift.is_lift {C : Type u} [category C] (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {D : Type u_1}
    [category D] (F : C ⥤ D)
    (H : ∀ (x y : C) (f₁ f₂ : x ⟶ y), r f₁ f₂ → functor.map F f₁ = functor.map F f₂) :
    functor r ⋙ lift r F H ≅ F :=
  nat_iso.of_components (fun (X : C) => iso.refl (functor.obj (functor r ⋙ lift r F H) X)) sorry

@[simp] theorem lift.is_lift_hom {C : Type u} [category C]
    (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {D : Type u_1} [category D] (F : C ⥤ D)
    (H : ∀ (x y : C) (f₁ f₂ : x ⟶ y), r f₁ f₂ → functor.map F f₁ = functor.map F f₂) (X : C) :
    nat_trans.app (iso.hom (lift.is_lift r F H)) X = 𝟙 :=
  rfl

@[simp] theorem lift.is_lift_inv {C : Type u} [category C]
    (r : {a b : C} → (a ⟶ b) → (a ⟶ b) → Prop) {D : Type u_1} [category D] (F : C ⥤ D)
    (H : ∀ (x y : C) (f₁ f₂ : x ⟶ y), r f₁ f₂ → functor.map F f₁ = functor.map F f₂) (X : C) :
    nat_trans.app (iso.inv (lift.is_lift r F H)) X = 𝟙 :=
  rfl

end Mathlib


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

! This file was ported from Lean 3 source module category_theory.monoidal.linear
! leanprover-community/mathlib commit 986c4d5761f938b2e1c43c01f001b6d9d88c2055
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.CategoryTheory.Linear.LinearFunctor
import Mathbin.CategoryTheory.Monoidal.Preadditive

/-!
# Linear monoidal categories

A monoidal category is `monoidal_linear R` if it is monoidal preadditive and
tensor product of morphisms is `R`-linear in both factors.
-/

namespace CategoryTheory

open CategoryTheory.Limits

open CategoryTheory.MonoidalCategory

variable (R : Type _) [Semiring R]

variable (C : Type _) [Category C] [Preadditive C] [Linear R C]

variable [MonoidalCategory C] [MonoidalPreadditive C]

#print CategoryTheory.MonoidalLinear /-
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/-- A category is `monoidal_linear R` if tensoring is `R`-linear in both factors.
-/
class MonoidalLinear : Prop where
  tensor_smul' : ∀ {W X Y Z : C} (f : W ⟶ X) (r : R) (g : Y ⟶ Z), f ⊗ r • g = r • (f ⊗ g) := by
    obviously
  smul_tensor' : ∀ {W X Y Z : C} (r : R) (f : W ⟶ X) (g : Y ⟶ Z), r • f ⊗ g = r • (f ⊗ g) := by
    obviously
#align category_theory.monoidal_linear CategoryTheory.MonoidalLinear
-/

restate_axiom monoidal_linear.tensor_smul'

restate_axiom monoidal_linear.smul_tensor'

attribute [simp] monoidal_linear.tensor_smul monoidal_linear.smul_tensor

variable {C} [MonoidalLinear R C]

#print CategoryTheory.tensorLeft_linear /-
instance tensorLeft_linear (X : C) : (tensorLeft X).Linear R where
#align category_theory.tensor_left_linear CategoryTheory.tensorLeft_linear
-/

#print CategoryTheory.tensorRight_linear /-
instance tensorRight_linear (X : C) : (tensorRight X).Linear R where
#align category_theory.tensor_right_linear CategoryTheory.tensorRight_linear
-/

/- warning: category_theory.tensoring_left_linear -> CategoryTheory.tensoringLeft_linear is a dubious translation:
lean 3 declaration is
  forall (R : Type.{u1}) [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u3, u2} C] [_inst_3 : CategoryTheory.Preadditive.{u3, u2} C _inst_2] [_inst_4 : CategoryTheory.Linear.{u1, u3, u2} R _inst_1 C _inst_2 _inst_3] [_inst_5 : CategoryTheory.MonoidalCategory.{u3, u2} C _inst_2] [_inst_6 : CategoryTheory.MonoidalPreadditive.{u2, u3} C _inst_2 _inst_3 _inst_5] [_inst_7 : CategoryTheory.MonoidalLinear.{u1, u2, u3} R _inst_1 C _inst_2 _inst_3 _inst_4 _inst_5 _inst_6] (X : C), CategoryTheory.Functor.Linear.{u1, u2, u2, u3, u3} R _inst_1 C C _inst_2 _inst_2 _inst_3 _inst_3 _inst_4 _inst_4 (CategoryTheory.Functor.obj.{u3, max u2 u3, u2, max u3 u2} C _inst_2 (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Functor.category.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.MonoidalCategory.tensoringLeft.{u3, u2} C _inst_2 _inst_5) X) (CategoryTheory.tensoringLeft_additive.{u2, u3} C _inst_2 _inst_3 _inst_5 _inst_6 X)
but is expected to have type
  forall (R : Type.{u1}) [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u3, u2} C] [_inst_3 : CategoryTheory.Preadditive.{u3, u2} C _inst_2] [_inst_4 : CategoryTheory.Linear.{u1, u3, u2} R _inst_1 C _inst_2 _inst_3] [_inst_5 : CategoryTheory.MonoidalCategory.{u3, u2} C _inst_2] [_inst_6 : CategoryTheory.MonoidalPreadditive.{u2, u3} C _inst_2 _inst_3 _inst_5] [_inst_7 : CategoryTheory.MonoidalLinear.{u1, u2, u3} R _inst_1 C _inst_2 _inst_3 _inst_4 _inst_5 _inst_6] (X : C), CategoryTheory.Functor.Linear.{u1, u2, u2, u3, u3} R _inst_1 C C _inst_2 _inst_2 _inst_3 _inst_3 _inst_4 _inst_4 (Prefunctor.obj.{succ u3, max (succ u2) (succ u3), u2, max u2 u3} C (CategoryTheory.CategoryStruct.toQuiver.{u3, u2} C (CategoryTheory.Category.toCategoryStruct.{u3, u2} C _inst_2)) (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u3, max u2 u3} (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Category.toCategoryStruct.{max u2 u3, max u2 u3} (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Functor.category.{u3, u3, u2, u2} C _inst_2 C _inst_2))) (CategoryTheory.Functor.toPrefunctor.{u3, max u2 u3, u2, max u2 u3} C _inst_2 (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Functor.category.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.MonoidalCategory.tensoringLeft.{u3, u2} C _inst_2 _inst_5)) X) (CategoryTheory.tensoringLeft_additive.{u2, u3} C _inst_2 _inst_3 _inst_5 _inst_6 X)
Case conversion may be inaccurate. Consider using '#align category_theory.tensoring_left_linear CategoryTheory.tensoringLeft_linearₓ'. -/
instance tensoringLeft_linear (X : C) : ((tensoringLeft C).obj X).Linear R where
#align category_theory.tensoring_left_linear CategoryTheory.tensoringLeft_linear

/- warning: category_theory.tensoring_right_linear -> CategoryTheory.tensoringRight_linear is a dubious translation:
lean 3 declaration is
  forall (R : Type.{u1}) [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u3, u2} C] [_inst_3 : CategoryTheory.Preadditive.{u3, u2} C _inst_2] [_inst_4 : CategoryTheory.Linear.{u1, u3, u2} R _inst_1 C _inst_2 _inst_3] [_inst_5 : CategoryTheory.MonoidalCategory.{u3, u2} C _inst_2] [_inst_6 : CategoryTheory.MonoidalPreadditive.{u2, u3} C _inst_2 _inst_3 _inst_5] [_inst_7 : CategoryTheory.MonoidalLinear.{u1, u2, u3} R _inst_1 C _inst_2 _inst_3 _inst_4 _inst_5 _inst_6] (X : C), CategoryTheory.Functor.Linear.{u1, u2, u2, u3, u3} R _inst_1 C C _inst_2 _inst_2 _inst_3 _inst_3 _inst_4 _inst_4 (CategoryTheory.Functor.obj.{u3, max u2 u3, u2, max u3 u2} C _inst_2 (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Functor.category.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.MonoidalCategory.tensoringRight.{u3, u2} C _inst_2 _inst_5) X) (CategoryTheory.tensoringRight_additive.{u2, u3} C _inst_2 _inst_3 _inst_5 _inst_6 X)
but is expected to have type
  forall (R : Type.{u1}) [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u3, u2} C] [_inst_3 : CategoryTheory.Preadditive.{u3, u2} C _inst_2] [_inst_4 : CategoryTheory.Linear.{u1, u3, u2} R _inst_1 C _inst_2 _inst_3] [_inst_5 : CategoryTheory.MonoidalCategory.{u3, u2} C _inst_2] [_inst_6 : CategoryTheory.MonoidalPreadditive.{u2, u3} C _inst_2 _inst_3 _inst_5] [_inst_7 : CategoryTheory.MonoidalLinear.{u1, u2, u3} R _inst_1 C _inst_2 _inst_3 _inst_4 _inst_5 _inst_6] (X : C), CategoryTheory.Functor.Linear.{u1, u2, u2, u3, u3} R _inst_1 C C _inst_2 _inst_2 _inst_3 _inst_3 _inst_4 _inst_4 (Prefunctor.obj.{succ u3, max (succ u2) (succ u3), u2, max u2 u3} C (CategoryTheory.CategoryStruct.toQuiver.{u3, u2} C (CategoryTheory.Category.toCategoryStruct.{u3, u2} C _inst_2)) (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u3, max u2 u3} (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Category.toCategoryStruct.{max u2 u3, max u2 u3} (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Functor.category.{u3, u3, u2, u2} C _inst_2 C _inst_2))) (CategoryTheory.Functor.toPrefunctor.{u3, max u2 u3, u2, max u2 u3} C _inst_2 (CategoryTheory.Functor.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.Functor.category.{u3, u3, u2, u2} C _inst_2 C _inst_2) (CategoryTheory.MonoidalCategory.tensoringRight.{u3, u2} C _inst_2 _inst_5)) X) (CategoryTheory.tensoringRight_additive.{u2, u3} C _inst_2 _inst_3 _inst_5 _inst_6 X)
Case conversion may be inaccurate. Consider using '#align category_theory.tensoring_right_linear CategoryTheory.tensoringRight_linearₓ'. -/
instance tensoringRight_linear (X : C) : ((tensoringRight C).obj X).Linear R where
#align category_theory.tensoring_right_linear CategoryTheory.tensoringRight_linear

/- warning: category_theory.monoidal_linear_of_faithful -> CategoryTheory.monoidalLinearOfFaithful is a dubious translation:
lean 3 declaration is
  forall (R : Type.{u1}) [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u3, u2} C] [_inst_3 : CategoryTheory.Preadditive.{u3, u2} C _inst_2] [_inst_4 : CategoryTheory.Linear.{u1, u3, u2} R _inst_1 C _inst_2 _inst_3] [_inst_5 : CategoryTheory.MonoidalCategory.{u3, u2} C _inst_2] [_inst_6 : CategoryTheory.MonoidalPreadditive.{u2, u3} C _inst_2 _inst_3 _inst_5] [_inst_7 : CategoryTheory.MonoidalLinear.{u1, u2, u3} R _inst_1 C _inst_2 _inst_3 _inst_4 _inst_5 _inst_6] {D : Type.{u4}} [_inst_8 : CategoryTheory.Category.{u5, u4} D] [_inst_9 : CategoryTheory.Preadditive.{u5, u4} D _inst_8] [_inst_10 : CategoryTheory.Linear.{u1, u5, u4} R _inst_1 D _inst_8 _inst_9] [_inst_11 : CategoryTheory.MonoidalCategory.{u5, u4} D _inst_8] [_inst_12 : CategoryTheory.MonoidalPreadditive.{u4, u5} D _inst_8 _inst_9 _inst_11] (F : CategoryTheory.MonoidalFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5) [_inst_13 : CategoryTheory.Faithful.{u5, u3, u4, u2} D _inst_8 C _inst_2 (CategoryTheory.LaxMonoidalFunctor.toFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5 (CategoryTheory.MonoidalFunctor.toLaxMonoidalFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5 F))] [_inst_14 : CategoryTheory.Functor.Additive.{u4, u2, u5, u3} D C _inst_8 _inst_2 _inst_9 _inst_3 (CategoryTheory.LaxMonoidalFunctor.toFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5 (CategoryTheory.MonoidalFunctor.toLaxMonoidalFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5 F))] [_inst_15 : CategoryTheory.Functor.Linear.{u1, u4, u2, u5, u3} R _inst_1 D C _inst_8 _inst_2 _inst_9 _inst_3 _inst_10 _inst_4 (CategoryTheory.LaxMonoidalFunctor.toFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5 (CategoryTheory.MonoidalFunctor.toLaxMonoidalFunctor.{u5, u3, u4, u2} D _inst_8 _inst_11 C _inst_2 _inst_5 F)) _inst_14], CategoryTheory.MonoidalLinear.{u1, u4, u5} R _inst_1 D _inst_8 _inst_9 _inst_10 _inst_11 _inst_12
but is expected to have type
  forall (R : Type.{u3}) [_inst_1 : Semiring.{u3} R] {C : Type.{u1}} [_inst_2 : CategoryTheory.Category.{u2, u1} C] [_inst_3 : CategoryTheory.Preadditive.{u2, u1} C _inst_2] [_inst_4 : CategoryTheory.Linear.{u3, u2, u1} R _inst_1 C _inst_2 _inst_3] [_inst_5 : CategoryTheory.MonoidalCategory.{u2, u1} C _inst_2] [_inst_6 : CategoryTheory.MonoidalPreadditive.{u1, u2} C _inst_2 _inst_3 _inst_5] [_inst_7 : CategoryTheory.MonoidalLinear.{u3, u1, u2} R _inst_1 C _inst_2 _inst_3 _inst_4 _inst_5 _inst_6] {D : Type.{u5}} [_inst_8 : CategoryTheory.Category.{u4, u5} D] [_inst_9 : CategoryTheory.Preadditive.{u4, u5} D _inst_8] [_inst_10 : CategoryTheory.Linear.{u3, u4, u5} R _inst_1 D _inst_8 _inst_9] [_inst_11 : CategoryTheory.MonoidalCategory.{u4, u5} D _inst_8] [_inst_12 : CategoryTheory.MonoidalPreadditive.{u5, u4} D _inst_8 _inst_9 _inst_11] (F : CategoryTheory.MonoidalFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5) [_inst_13 : CategoryTheory.Faithful.{u4, u2, u5, u1} D _inst_8 C _inst_2 (CategoryTheory.LaxMonoidalFunctor.toFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5 (CategoryTheory.MonoidalFunctor.toLaxMonoidalFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5 F))] [_inst_14 : CategoryTheory.Functor.Additive.{u5, u1, u4, u2} D C _inst_8 _inst_2 _inst_9 _inst_3 (CategoryTheory.LaxMonoidalFunctor.toFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5 (CategoryTheory.MonoidalFunctor.toLaxMonoidalFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5 F))] [_inst_15 : CategoryTheory.Functor.Linear.{u3, u5, u1, u4, u2} R _inst_1 D C _inst_8 _inst_2 _inst_9 _inst_3 _inst_10 _inst_4 (CategoryTheory.LaxMonoidalFunctor.toFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5 (CategoryTheory.MonoidalFunctor.toLaxMonoidalFunctor.{u4, u2, u5, u1} D _inst_8 _inst_11 C _inst_2 _inst_5 F)) _inst_14], CategoryTheory.MonoidalLinear.{u3, u5, u4} R _inst_1 D _inst_8 _inst_9 _inst_10 _inst_11 _inst_12
Case conversion may be inaccurate. Consider using '#align category_theory.monoidal_linear_of_faithful CategoryTheory.monoidalLinearOfFaithfulₓ'. -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/-- A faithful linear monoidal functor to a linear monoidal category
ensures that the domain is linear monoidal. -/
theorem monoidalLinearOfFaithful {D : Type _} [Category D] [Preadditive D] [Linear R D]
    [MonoidalCategory D] [MonoidalPreadditive D] (F : MonoidalFunctor D C) [Faithful F.toFunctor]
    [F.toFunctor.Additive] [F.toFunctor.Linear R] : MonoidalLinear R D :=
  { tensor_smul' := by
      intros
      apply F.to_functor.map_injective
      simp only [F.to_functor.map_smul r (f ⊗ g), F.to_functor.map_smul r g, F.map_tensor,
        monoidal_linear.tensor_smul, linear.smul_comp, linear.comp_smul]
    smul_tensor' := by
      intros
      apply F.to_functor.map_injective
      simp only [F.to_functor.map_smul r (f ⊗ g), F.to_functor.map_smul r f, F.map_tensor,
        monoidal_linear.smul_tensor, linear.smul_comp, linear.comp_smul] }
#align category_theory.monoidal_linear_of_faithful CategoryTheory.monoidalLinearOfFaithful

end CategoryTheory


/-
Copyright (c) 2020 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Scott Morrison
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.category_theory.category.default
import Mathlib.data.equiv.functor
import Mathlib.PostPort

universes u₀ u₁ l

namespace Mathlib

/-!
# Functions functorial with respect to equivalences

An `equiv_functor` is a function from `Type → Type` equipped with the additional data of
coherently mapping equivalences to equivalences.

In categorical language, it is an endofunctor of the "core" of the category `Type`.
-/

/--
An `equiv_functor` is only functorial with respect to equivalences.

To construct an `equiv_functor`, it suffices to supply just the function `f α → f β` from
an equivalence `α ≃ β`, and then prove the functor laws. It's then a consequence that
this function is part of an equivalence, provided by `equiv_functor.map_equiv`.
-/
class equiv_functor (f : Type u₀ → Type u₁)
where
  map : {α β : Type u₀} → α ≃ β → f α → f β
  map_refl' : autoParam (∀ (α : Type u₀), map (equiv.refl α) = id)
  (Lean.Syntax.ident Lean.SourceInfo.none (String.toSubstring "Mathlib.obviously")
    (Lean.Name.mkStr (Lean.Name.mkStr Lean.Name.anonymous "Mathlib") "obviously") [])
  map_trans' : autoParam (∀ {α β γ : Type u₀} (k : α ≃ β) (h : β ≃ γ), map (equiv.trans k h) = map h ∘ map k)
  (Lean.Syntax.ident Lean.SourceInfo.none (String.toSubstring "Mathlib.obviously")
    (Lean.Name.mkStr (Lean.Name.mkStr Lean.Name.anonymous "Mathlib") "obviously") [])

@[simp] theorem equiv_functor.map_refl {f : Type u₀ → Type u₁} [c : equiv_functor f] (α : Type u₀) : equiv_functor.map (equiv.refl α) = id := sorry

theorem equiv_functor.map_trans {f : Type u₀ → Type u₁} [c : equiv_functor f] {α : Type u₀} {β : Type u₀} {γ : Type u₀} (k : α ≃ β) (h : β ≃ γ) : equiv_functor.map (equiv.trans k h) = equiv_functor.map h ∘ equiv_functor.map k := sorry

namespace equiv_functor

/-- An `equiv_functor` in fact takes every equiv to an equiv. -/
def map_equiv (f : Type u₀ → Type u₁) [equiv_functor f] {α : Type u₀} {β : Type u₀} (e : α ≃ β) : f α ≃ f β :=
  equiv.mk (map e) (map (equiv.symm e)) sorry sorry

@[simp] theorem map_equiv_apply (f : Type u₀ → Type u₁) [equiv_functor f] {α : Type u₀} {β : Type u₀} (e : α ≃ β) (x : f α) : coe_fn (map_equiv f e) x = map e x :=
  rfl

theorem map_equiv_symm_apply (f : Type u₀ → Type u₁) [equiv_functor f] {α : Type u₀} {β : Type u₀} (e : α ≃ β) (y : f β) : coe_fn (equiv.symm (map_equiv f e)) y = map (equiv.symm e) y :=
  rfl

@[simp] theorem map_equiv_refl (f : Type u₀ → Type u₁) [equiv_functor f] (α : Type u₀) : map_equiv f (equiv.refl α) = equiv.refl (f α) := sorry

@[simp] theorem map_equiv_symm (f : Type u₀ → Type u₁) [equiv_functor f] {α : Type u₀} {β : Type u₀} (e : α ≃ β) : equiv.symm (map_equiv f e) = map_equiv f (equiv.symm e) :=
  equiv.ext (map_equiv_symm_apply f e)

/--
The composition of `map_equiv`s is carried over the `equiv_functor`.
For plain `functor`s, this lemma is named `map_map` when applied
or `map_comp_map` when not applied.
-/
@[simp] theorem map_equiv_trans (f : Type u₀ → Type u₁) [equiv_functor f] {α : Type u₀} {β : Type u₀} {γ : Type u₀} (ab : α ≃ β) (bc : β ≃ γ) : equiv.trans (map_equiv f ab) (map_equiv f bc) = map_equiv f (equiv.trans ab bc) := sorry

protected instance of_is_lawful_functor (f : Type u₀ → Type u₁) [Functor f] [is_lawful_functor f] : equiv_functor f :=
  mk fun (α β : Type u₀) (e : α ≃ β) => Functor.map ⇑e

theorem map_equiv.injective (f : Type u₀ → Type u₁) [Applicative f] [is_lawful_applicative f] {α : Type u₀} {β : Type u₀} (h : Type u₀ → function.injective pure) : function.injective (map_equiv f) := sorry


/-
Copyright (c) 2018 Andreas Swerdlow. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Andreas Swerdlow

! This file was ported from Lean 3 source module deprecated.subfield
! leanprover-community/mathlib commit 23aa88e32dcc9d2a24cca7bc23268567ed4cd7d6
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Deprecated.Subring

/-!
# Unbundled subfields (deprecated)

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

This file is deprecated, and is no longer imported by anything in mathlib other than other
deprecated files, and test files. You should not need to import it.

This file defines predicates for unbundled subfields. Instead of using this file, please use
`subfield`, defined in `field_theory.subfield`, for subfields of fields.

## Main definitions

`is_subfield (S : set F) : Prop` : the predicate that `S` is the underlying set of a subfield
of the field `F`. The bundled variant `subfield F` should be used in preference to this.

## Tags

is_subfield
-/

variable {F : Type _} [Field F] (S : Set F)

#print IsSubfield /-
/-- `is_subfield (S : set F)` is the predicate saying that a given subset of a field is
the set underlying a subfield. This structure is deprecated; use the bundled variant
`subfield F` to model subfields of a field. -/
structure IsSubfield extends IsSubring S : Prop where
  inv_mem : ∀ {x : F}, x ∈ S → x⁻¹ ∈ S
#align is_subfield IsSubfield
-/

/- warning: is_subfield.div_mem -> IsSubfield.div_mem is a dubious translation:
lean 3 declaration is
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {S : Set.{u1} F}, (IsSubfield.{u1} F _inst_1 S) -> (forall {x : F} {y : F}, (Membership.Mem.{u1, u1} F (Set.{u1} F) (Set.hasMem.{u1} F) x S) -> (Membership.Mem.{u1, u1} F (Set.{u1} F) (Set.hasMem.{u1} F) y S) -> (Membership.Mem.{u1, u1} F (Set.{u1} F) (Set.hasMem.{u1} F) (HDiv.hDiv.{u1, u1, u1} F F F (instHDiv.{u1} F (DivInvMonoid.toHasDiv.{u1} F (DivisionRing.toDivInvMonoid.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) x y) S))
but is expected to have type
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {S : Set.{u1} F}, (IsSubfield.{u1} F _inst_1 S) -> (forall {x : F} {y : F}, (Membership.mem.{u1, u1} F (Set.{u1} F) (Set.instMembershipSet.{u1} F) x S) -> (Membership.mem.{u1, u1} F (Set.{u1} F) (Set.instMembershipSet.{u1} F) y S) -> (Membership.mem.{u1, u1} F (Set.{u1} F) (Set.instMembershipSet.{u1} F) (HDiv.hDiv.{u1, u1, u1} F F F (instHDiv.{u1} F (Field.toDiv.{u1} F _inst_1)) x y) S))
Case conversion may be inaccurate. Consider using '#align is_subfield.div_mem IsSubfield.div_memₓ'. -/
theorem IsSubfield.div_mem {S : Set F} (hS : IsSubfield S) {x y : F} (hx : x ∈ S) (hy : y ∈ S) :
    x / y ∈ S := by
  rw [div_eq_mul_inv]
  exact hS.to_is_subring.to_is_submonoid.mul_mem hx (hS.inv_mem hy)
#align is_subfield.div_mem IsSubfield.div_mem

#print IsSubfield.pow_mem /-
theorem IsSubfield.pow_mem {a : F} {n : ℤ} {s : Set F} (hs : IsSubfield s) (h : a ∈ s) :
    a ^ n ∈ s := by
  cases n
  · rw [zpow_ofNat]
    exact hs.to_is_subring.to_is_submonoid.pow_mem h
  · rw [zpow_negSucc]
    exact hs.inv_mem (hs.to_is_subring.to_is_submonoid.pow_mem h)
#align is_subfield.pow_mem IsSubfield.pow_mem
-/

#print Univ.isSubfield /-
theorem Univ.isSubfield : IsSubfield (@Set.univ F) :=
  { Univ.isSubmonoid, IsAddSubgroup.univ_addSubgroup with inv_mem := by intros <;> trivial }
#align univ.is_subfield Univ.isSubfield
-/

/- warning: preimage.is_subfield -> Preimage.isSubfield is a dubious translation:
lean 3 declaration is
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {K : Type.{u2}} [_inst_2 : Field.{u2} K] (f : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) {s : Set.{u2} K}, (IsSubfield.{u2} K _inst_2 s) -> (IsSubfield.{u1} F _inst_1 (Set.preimage.{u1, u2} F K (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) (fun (_x : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) => F -> K) (RingHom.hasCoeToFun.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) f) s))
but is expected to have type
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {K : Type.{u2}} [_inst_2 : Field.{u2} K] (f : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) {s : Set.{u2} K}, (IsSubfield.{u2} K _inst_2 s) -> (IsSubfield.{u1} F _inst_1 (Set.preimage.{u1, u2} F K (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F (fun (_x : F) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : F) => K) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonUnitalNonAssocSemiring.toMul.{u1} F (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} F (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))))) (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} F (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1))))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))) (RingHom.instRingHomClassRingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))))))) f) s))
Case conversion may be inaccurate. Consider using '#align preimage.is_subfield Preimage.isSubfieldₓ'. -/
theorem Preimage.isSubfield {K : Type _} [Field K] (f : F →+* K) {s : Set K} (hs : IsSubfield s) :
    IsSubfield (f ⁻¹' s) :=
  { f.isSubring_preimage hs.to_isSubring with
    inv_mem := fun a (ha : f a ∈ s) =>
      show f a⁻¹ ∈ s by
        rw [map_inv₀]
        exact hs.inv_mem ha }
#align preimage.is_subfield Preimage.isSubfield

/- warning: image.is_subfield -> Image.isSubfield is a dubious translation:
lean 3 declaration is
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {K : Type.{u2}} [_inst_2 : Field.{u2} K] (f : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) {s : Set.{u1} F}, (IsSubfield.{u1} F _inst_1 s) -> (IsSubfield.{u2} K _inst_2 (Set.image.{u1, u2} F K (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) (fun (_x : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) => F -> K) (RingHom.hasCoeToFun.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) f) s))
but is expected to have type
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {K : Type.{u2}} [_inst_2 : Field.{u2} K] (f : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) {s : Set.{u1} F}, (IsSubfield.{u1} F _inst_1 s) -> (IsSubfield.{u2} K _inst_2 (Set.image.{u1, u2} F K (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F (fun (_x : F) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : F) => K) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonUnitalNonAssocSemiring.toMul.{u1} F (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} F (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))))) (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} F (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1))))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))) (RingHom.instRingHomClassRingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))))))) f) s))
Case conversion may be inaccurate. Consider using '#align image.is_subfield Image.isSubfieldₓ'. -/
theorem Image.isSubfield {K : Type _} [Field K] (f : F →+* K) {s : Set F} (hs : IsSubfield s) :
    IsSubfield (f '' s) :=
  { f.isSubring_image hs.to_isSubring with
    inv_mem := fun a ⟨x, xmem, ha⟩ => ⟨x⁻¹, hs.inv_mem xmem, ha ▸ map_inv₀ f _⟩ }
#align image.is_subfield Image.isSubfield

/- warning: range.is_subfield -> Range.isSubfield is a dubious translation:
lean 3 declaration is
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {K : Type.{u2}} [_inst_2 : Field.{u2} K] (f : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))), IsSubfield.{u2} K _inst_2 (Set.range.{u2, succ u1} K F (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) (fun (_x : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) => F -> K) (RingHom.hasCoeToFun.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) f))
but is expected to have type
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {K : Type.{u2}} [_inst_2 : Field.{u2} K] (f : RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))), IsSubfield.{u2} K _inst_2 (Set.range.{u2, succ u1} K F (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F (fun (_x : F) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : F) => K) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonUnitalNonAssocSemiring.toMul.{u1} F (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} F (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))))) (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} F (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1))))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2))))) F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))) (RingHom.instRingHomClassRingHom.{u1, u2} F K (NonAssocRing.toNonAssocSemiring.{u1} F (Ring.toNonAssocRing.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1)))) (NonAssocRing.toNonAssocSemiring.{u2} K (Ring.toNonAssocRing.{u2} K (DivisionRing.toRing.{u2} K (Field.toDivisionRing.{u2} K _inst_2)))))))) f))
Case conversion may be inaccurate. Consider using '#align range.is_subfield Range.isSubfieldₓ'. -/
theorem Range.isSubfield {K : Type _} [Field K] (f : F →+* K) : IsSubfield (Set.range f) :=
  by
  rw [← Set.image_univ]
  apply Image.isSubfield _ Univ.isSubfield
#align range.is_subfield Range.isSubfield

namespace Field

#print Field.closure /-
/-- `field.closure s` is the minimal subfield that includes `s`. -/
def closure : Set F :=
  { x | ∃ y ∈ Ring.closure S, ∃ z ∈ Ring.closure S, y / z = x }
#align field.closure Field.closure
-/

variable {S}

#print Field.ring_closure_subset /-
theorem ring_closure_subset : Ring.closure S ⊆ closure S := fun x hx =>
  ⟨x, hx, 1, Ring.closure.isSubring.to_isSubmonoid.one_mem, div_one x⟩
#align field.ring_closure_subset Field.ring_closure_subset
-/

/- warning: field.closure.is_submonoid -> Field.closure.isSubmonoid is a dubious translation:
lean 3 declaration is
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {S : Set.{u1} F}, IsSubmonoid.{u1} F (Ring.toMonoid.{u1} F (DivisionRing.toRing.{u1} F (Field.toDivisionRing.{u1} F _inst_1))) (Field.closure.{u1} F _inst_1 S)
but is expected to have type
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {S : Set.{u1} F}, IsSubmonoid.{u1} F (MonoidWithZero.toMonoid.{u1} F (Semiring.toMonoidWithZero.{u1} F (DivisionSemiring.toSemiring.{u1} F (Semifield.toDivisionSemiring.{u1} F (Field.toSemifield.{u1} F _inst_1))))) (Field.closure.{u1} F _inst_1 S)
Case conversion may be inaccurate. Consider using '#align field.closure.is_submonoid Field.closure.isSubmonoidₓ'. -/
theorem closure.isSubmonoid : IsSubmonoid (closure S) :=
  { mul_mem := by
      rintro _ _ ⟨p, hp, q, hq, hq0, rfl⟩ ⟨r, hr, s, hs, hs0, rfl⟩ <;>
        exact
          ⟨p * r, IsSubmonoid.mul_mem ring.closure.is_subring.to_is_submonoid hp hr, q * s,
            IsSubmonoid.mul_mem ring.closure.is_subring.to_is_submonoid hq hs,
            (div_mul_div_comm _ _ _ _).symm⟩
    one_mem := ring_closure_subset <| IsSubmonoid.one_mem Ring.closure.isSubring.to_isSubmonoid }
#align field.closure.is_submonoid Field.closure.isSubmonoid

#print Field.closure.isSubfield /-
theorem closure.isSubfield : IsSubfield (closure S) :=
  have h0 : (0 : F) ∈ closure S :=
    ring_closure_subset <| Ring.closure.isSubring.to_isAddSubgroup.to_isAddSubmonoid.zero_mem
  {
    closure.isSubmonoid with
    add_mem := by
      intro a b ha hb
      rcases id ha with ⟨p, hp, q, hq, rfl⟩
      rcases id hb with ⟨r, hr, s, hs, rfl⟩
      classical
        by_cases hq0 : q = 0
        · simp [hb, hq0]
        by_cases hs0 : s = 0
        · simp [ha, hs0]
        exact
          ⟨p * s + q * r,
            IsAddSubmonoid.add_mem ring.closure.is_subring.to_is_add_subgroup.to_is_add_submonoid
              (ring.closure.is_subring.to_is_submonoid.mul_mem hp hs)
              (ring.closure.is_subring.to_is_submonoid.mul_mem hq hr),
            q * s, ring.closure.is_subring.to_is_submonoid.mul_mem hq hs,
            (div_add_div p r hq0 hs0).symm⟩
    zero_mem := h0
    neg_mem := by
      rintro _ ⟨p, hp, q, hq, rfl⟩
      exact ⟨-p, ring.closure.is_subring.to_is_add_subgroup.neg_mem hp, q, hq, neg_div q p⟩
    inv_mem := by
      rintro _ ⟨p, hp, q, hq, rfl⟩
      exact ⟨q, hq, p, hp, (inv_div _ _).symm⟩ }
#align field.closure.is_subfield Field.closure.isSubfield
-/

#print Field.mem_closure /-
theorem mem_closure {a : F} (ha : a ∈ S) : a ∈ closure S :=
  ring_closure_subset <| Ring.mem_closure ha
#align field.mem_closure Field.mem_closure
-/

#print Field.subset_closure /-
theorem subset_closure : S ⊆ closure S := fun _ => mem_closure
#align field.subset_closure Field.subset_closure
-/

#print Field.closure_subset /-
theorem closure_subset {T : Set F} (hT : IsSubfield T) (H : S ⊆ T) : closure S ⊆ T := by
  rintro _ ⟨p, hp, q, hq, hq0, rfl⟩ <;>
    exact
      hT.div_mem (Ring.closure_subset hT.to_is_subring H hp)
        (Ring.closure_subset hT.to_is_subring H hq)
#align field.closure_subset Field.closure_subset
-/

#print Field.closure_subset_iff /-
theorem closure_subset_iff {s t : Set F} (ht : IsSubfield t) : closure s ⊆ t ↔ s ⊆ t :=
  ⟨Set.Subset.trans subset_closure, closure_subset ht⟩
#align field.closure_subset_iff Field.closure_subset_iff
-/

#print Field.closure_mono /-
theorem closure_mono {s t : Set F} (H : s ⊆ t) : closure s ⊆ closure t :=
  closure_subset closure.isSubfield <| Set.Subset.trans H subset_closure
#align field.closure_mono Field.closure_mono
-/

end Field

#print isSubfield_unionᵢ_of_directed /-
theorem isSubfield_unionᵢ_of_directed {ι : Type _} [hι : Nonempty ι] {s : ι → Set F}
    (hs : ∀ i, IsSubfield (s i)) (directed : ∀ i j, ∃ k, s i ⊆ s k ∧ s j ⊆ s k) :
    IsSubfield (⋃ i, s i) :=
  { inv_mem := fun x hx =>
      let ⟨i, hi⟩ := Set.mem_unionᵢ.1 hx
      Set.mem_unionᵢ.2 ⟨i, (hs i).inv_mem hi⟩
    to_isSubring := isSubring_unionᵢ_of_directed (fun i => (hs i).to_isSubring) Directed }
#align is_subfield_Union_of_directed isSubfield_unionᵢ_of_directed
-/

/- warning: is_subfield.inter -> IsSubfield.inter is a dubious translation:
lean 3 declaration is
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {S₁ : Set.{u1} F} {S₂ : Set.{u1} F}, (IsSubfield.{u1} F _inst_1 S₁) -> (IsSubfield.{u1} F _inst_1 S₂) -> (IsSubfield.{u1} F _inst_1 (Inter.inter.{u1} (Set.{u1} F) (Set.hasInter.{u1} F) S₁ S₂))
but is expected to have type
  forall {F : Type.{u1}} [_inst_1 : Field.{u1} F] {S₁ : Set.{u1} F} {S₂ : Set.{u1} F}, (IsSubfield.{u1} F _inst_1 S₁) -> (IsSubfield.{u1} F _inst_1 S₂) -> (IsSubfield.{u1} F _inst_1 (Inter.inter.{u1} (Set.{u1} F) (Set.instInterSet.{u1} F) S₁ S₂))
Case conversion may be inaccurate. Consider using '#align is_subfield.inter IsSubfield.interₓ'. -/
theorem IsSubfield.inter {S₁ S₂ : Set F} (hS₁ : IsSubfield S₁) (hS₂ : IsSubfield S₂) :
    IsSubfield (S₁ ∩ S₂) :=
  { IsSubring.inter hS₁.to_isSubring hS₂.to_isSubring with
    inv_mem := fun x hx => ⟨hS₁.inv_mem hx.1, hS₂.inv_mem hx.2⟩ }
#align is_subfield.inter IsSubfield.inter

#print IsSubfield.interᵢ /-
theorem IsSubfield.interᵢ {ι : Sort _} {S : ι → Set F} (h : ∀ y : ι, IsSubfield (S y)) :
    IsSubfield (Set.interᵢ S) :=
  { IsSubring.interᵢ fun y => (h y).to_isSubring with
    inv_mem := fun x hx => Set.mem_interᵢ.2 fun y => (h y).inv_mem <| Set.mem_interᵢ.1 hx y }
#align is_subfield.Inter IsSubfield.interᵢ
-/


import rigid_elements.preadditive_conditions
import mul_subgroup.adjoin

variables {K : Type*} [field K]

open rigid_pair

def mul_subgroup.exceptional (T : mul_subgroup K) :=
(∀ x : K, ¬ (T.rigid x ∧ T.rigid (-x)) → x ∈ T ∨ -x ∈ T) ∧
((-1 : K) ∈ T ∨ ∀ (x y : K), x ∈ T → y ∈ T → x + y ∈ T)

theorem rigid_pair.preadditive_of_not_exceptional
  {T H : mul_subgroup K}
  (rp : rigid_pair T H)
  (H : ¬ T.exceptional) :
  rp.preadditive :=
begin
  suffices : (∃ (a : K) (ha1 : a ≠ 0) (ha2 : a ∉ T), ¬ T.rigid (-a)),
  { obtain ⟨a,ha1,ha2,hh⟩ := this,
    exact rp.preadditive_of_nmem_of_neg_not_rigid a ha1 ha2 hh },
  by_contra c, push_neg at c,
  apply H,
  split,
  { intros x hx, rw not_and_distrib at hx, cases hx,
    { have hxz : x ≠ 0,
      { dsimp [mul_subgroup.rigid] at hx, push_neg at hx,
        obtain ⟨a,b,ha,hb,hx1,hx2,hx3⟩ := hx,
        assumption },
      specialize c (-x) (by simpa),
      rw neg_neg at c,
      right,
      by_contra cc, apply hx, apply c cc },
    { have hxz : x ≠ 0,
      { dsimp [mul_subgroup.rigid] at hx, push_neg at hx,
        obtain ⟨a,b,ha,hb,hx1,hx2,hx3⟩ := hx,
        simpa using hx1 },
      specialize c x hxz,
      left,
      by_contra cc, apply hx, apply c cc } },
  { by_cases hn : (-1 : K) ∈ T, { left, assumption },
    right,
    intros x y hx hy,
    specialize c (-1) (by simp) hn, rw neg_neg at c,
    specialize c x y hx hy (by simp),
    cases c,
    { simpa using c },
    { simpa using c } }
end

-- Claim (*) on page 458
lemma rigid_pair.exists_preadditive_aux
  {T H : mul_subgroup K}
  (rp : rigid_pair T H) :
  ∀ (a b : K), a ∈ rp.OO_m → b ∈ rp.OO_m → (1 - a * b ∉ T) →
  (-a)⁻¹ * (1 - a * b) ∈ T :=
begin
  intros a b ha hb hh,
  have haz : (-a) ≠ 0,
  { intro c, apply hh, rw neg_eq_zero at c, simp [c, T.one_mem] },
  have haz' : a ≠ 0, by simpa using haz,
  have := rp.neg a ha.1 (1+a) (1+b) ha.2 hb.2 _,
  swap,
  { intro c, apply hh, rw neg_eq_zero at c, simp [c, T.one_mem] },
  cases this,
  { exfalso, apply hh, convert this, ring },
  convert this, field_simp, left, ring,
end

lemma rigid_pair.exists_preadditive_aux'
  {T H : mul_subgroup K}
  (rp : rigid_pair T H) :
  ∀ (a b : K), a ∈ rp.OO_m → b ∈ rp.OO_m → (1 - a * b ∉ T) →
  a * b⁻¹ ∈ T :=
begin
  intros a b ha hb hh,
  have h1 := rp.exists_preadditive_aux a b ha hb hh,
  have h2 := rp.exists_preadditive_aux b a hb ha (by rwa mul_comm),
  convert T.mul_mem (T.inv_mem h1) h2 using 1,
  have : b ≠ 0,
  { intro c, apply T.ne_zero_of_mem h2, simp [c] },
  have : a ≠ 0,
  { intro c, apply T.ne_zero_of_mem h1, simp [c] },
  have : 1 - a * b ≠ 0,
  { intro c, apply T.ne_zero_of_mem h1, simp [c] },
  field_simp, ring,
end

lemma rigid_pair.OO_m_mono {T H H' : mul_subgroup K}
  (rp : rigid_pair T H) (h : H ≤ H') :
  (rp.of_le H' h).OO_m ≤ rp.OO_m :=
begin
  rintros x ⟨h1,h2⟩,
  exact ⟨λ c, h1 (h c), h2⟩,
end

theorem rigid_pair.exists_preadditive
  {T H : mul_subgroup K}
  (rp : rigid_pair T H) :
  ∃ (x : K) (hx : x ≠ 0) (hxH : x * x ∈ H),
  (rp.of_le _ (H.le_adjoin_ne_zero x hx)).preadditive :=
begin
  by_cases HH : rp.preadditive,
  { use [1, one_ne_zero], split, { rw mul_one, exact H.one_mem },
    convert HH,
    exact H.adjoin_ne_zero_eq_of_mem 1 one_ne_zero H.one_mem },
  --have HT : T.exceptional,
  --{ by_contra c, apply HH, apply rigid_pair.preadditive_of_not_exceptional _ c },
  rw rp.preadditive_iff at HH,
  push_neg at HH,
  obtain ⟨a,b,ha,hb,HH⟩ := HH,
  have haz : a ≠ 0,
  { intro c, apply HH, simp [c, T.one_mem] },
  use [a, haz],
  let rp' := rp.of_le _ (H.le_adjoin_ne_zero a haz),
  let H' := H.adjoin_ne_zero a haz,
  change _ ∧ rp'.preadditive,
  let t := (-a)⁻¹ * (1 - a * b),
  have aux1 : t ∈ T := rp.exists_preadditive_aux a b ha hb HH,
  have haz' : (-a) ≠ 0, { simpa },
  have h1 : 1 - a * b = (-a) * t, by { dsimp [t], field_simp, ring },
  have h2 : a * b = 1 + a * t,
  { rw [neg_mul] at h1, apply_fun (λ e, -e) at h1, rw neg_neg at h1, rw ← h1, ring },
  have h3 := rp.pos a ha.1 1 t T.one_mem aux1 haz,
  rw ← h2 at h3,
  cases h3,
  swap,
  { exfalso,
    apply hb.1, apply rp.le, dsimp [t] at h3,
    convert h3, field_simp, ring },
  have hbz : b ≠ 0,
  { intro c, apply T.ne_zero_of_mem h3, simp [c] },
  split,
  { apply rp.le,
    have := rp.exists_preadditive_aux' a b ha hb HH,
    convert T.mul_mem h3 this using 1, field_simp, ring },
  { apply rigid_pair.preadditive_of_exists_UU _ (-a),
    swap, { intro c, apply ha.1, rw ← neg_neg a, apply rp.le_neg c, },
    suffices : ∀ z : K, z ∈ rp'.OO_m → 1 - a * z ∈ T ∧ 1 - a⁻¹ * z ∈ T,
    { split,
      { split,
        apply rp'.neg_mem_of_mem, exact H.mem_adjoin_ne_zero_self _ _,
        intros y hy,
        specialize this y hy,
        split,
        { intro c,
          apply hy.1, rw (show y = (-a)⁻¹ * (-a * y), by field_simp; ring),
          apply mul_subgroup.mul_mem,
          apply mul_subgroup.inv_mem,
          apply rp'.neg_mem_of_mem,
          exact H.mem_adjoin_ne_zero_self _ _,
          exact c },
        { convert this.1, ring } },
      { split,
        apply mul_subgroup.inv_mem, apply rp'.neg_mem_of_mem,
        exact H.mem_adjoin_ne_zero_self _ _,
        intros y hy,
        specialize this y hy,
        split,
        { intro c,
          apply hy.1, rw (show y = (-a) * ((-a)⁻¹ * y), by field_simp; ring),
          apply mul_subgroup.mul_mem,
          apply rp'.neg_mem_of_mem, exact H.mem_adjoin_ne_zero_self _ _,
          exact c },
        { convert this.2, rw [inv_neg], ring } } },
    intros z hz,
    by_cases hzz : z = 0, { simp [hzz, T.one_mem] },
    split,
    { by_contra c,
      have := rp.exists_preadditive_aux' a z ha (rp.OO_m_mono _ hz) c,
      apply hz.1, replace this := rp'.le this,
      convert H'.mul_mem (H.mem_adjoin_ne_zero_self a haz) (H'.inv_mem this),
      field_simp, ring },
    have hh : 1 - b * z ∈ T,
    { by_contra c,
      have := rp.exists_preadditive_aux' b z hb (rp.OO_m_mono _ hz) c,
      apply hz.1, replace this := rp'.le this,
      convert H'.mul_mem (_ : b ∈ H') (H'.inv_mem this),
      field_simp, ring,
      { suffices : a * b ∈ H',
        { convert H'.mul_mem this (H'.inv_mem (H.mem_adjoin_ne_zero_self a haz)),
          field_simp, ring },
        apply rp'.le, exact h3 } },
    by_contra c, apply hz.1,
    have c' : ((-a) * z⁻¹)⁻¹ ∉ rp'.OO_m,
    { dsimp [rigid_pair.OO_m], push_neg, intro _, convert c, field_simp, ring },
    rw ← rp'.OO_m_mem_iff_inv_nmem at c',
    have e1 := rp.exists_preadditive_aux (-a * z⁻¹) (-b * z) (rp.OO_m_mono _ c') _ _,
    have e2 := rp.exists_preadditive_aux a b ha hb HH,
    rw ← inv_inv z, apply mul_subgroup.inv_mem,
    apply rp'.mem_of_neg_mem, apply rp'.le,
    have : 1 - -a * z⁻¹ * (-b * z) = (1 - a * b), by field_simp; ring, rw this at e1, clear this,
    convert T.mul_mem e2 (T.inv_mem e1),
    rw [mul_inv, mul_comm, mul_assoc,
      mul_comm _ (1 - a * b), ← mul_assoc _ (1 - a * b), inv_mul_cancel],
    field_simp, ring,
    { intro c, apply T.ne_zero_of_mem e2, simp [c] },
    { apply rp.OO_m_mono (H.le_adjoin_ne_zero a haz),
      split,
      { intro c, apply hz.1,
        convert H'.mul_mem c (H'.inv_mem (_ : -b ∈ H')),
        have : -b ≠ 0, by simpa,
        field_simp, ring,
        apply rp'.neg_mem_of_mem,
        have : b * a⁻¹ ∈ H',
        { apply rp'.le,
          apply rp.exists_preadditive_aux' b a hb ha (by rwa mul_comm) },
        convert H'.mul_mem this (H.mem_adjoin_ne_zero_self _ _), field_simp },
      { convert hh, ring } },
    { convert HH using 2, field_simp, ring },
    { simp only [ne.def, neg_eq_zero, mul_eq_zero, inv_eq_zero], push_neg,
      exact ⟨haz, hzz⟩ },
    { intro c, apply hz.1,
      convert H'.mul_mem (H'.inv_mem c) (_ : (-a) ∈ H'), field_simp,
      apply rp'.neg_mem_of_mem, exact H.mem_adjoin_ne_zero_self _ _ } }
end


import ..expressions.time_expr_current

open lang.time
/-
Stress test of alternate API

First Frames, then Spaces,
Duration, Time, Transforms

Type error demonstrations on bottom
-/

def

--check frame API
def std_fr : time_frame_expr := [time_std_frame K]
def fr_var : time_frame_var := ⟨⟨"std"⟩⟩ --hide with function?
def fr_var_expr := time_frame_expr.var fr_var
#check fr_var_expr.value
lemma defaultedfr : fr_var_expr.value = time_std_frame K := rfl

--check space API
def std_sp : time_space_expr std_fr :=  [time_std_space K]
def std_var : time_space_expr std_fr := time_space_expr.var ⟨⟨"std"⟩⟩
lemma defaultsp : std_var.value = std_sp.value := rfl

--out of sequence but required to test derived API
def launch_time :
  time_expr std_sp
  :=
  [(mk_time std_sp.value 0)]
def one_second :=
  [(mk_duration std_sp.value 1)]

--test derived API
--This is not deeply embedded. Evaluates launch time and one second to build a new frame.
--This is a trade-off caused because time frame expressions are defined prior to point and vector expressions,
--in order to allow points and vectors to depend on space expressions rather than phys space literal values,
--encapsulating phys inside of lang
def mission_frame : time_frame_expr  :=
    mk_time_frame_expr launch_time one_second

--use this or literal constructor (this function uses a different constructor than [])
def mission_space :=
  mk_time_space_expr mission_frame --(mk_space ℚ mission_frame.value)

--move on to durations and times
def dur_zero : duration_expr std_sp := 0 --duration.zero
def dur_one : duration_expr std_sp := 1 --duration.one
def dur_lit : duration_expr std_sp := [one_second.value]
def dur_var : duration_expr std_sp := duration_expr.var ⟨⟨"dur"⟩⟩ -- var constructor should have notation?
def dur_add  : duration_expr std_sp := one_second +ᵥ one_second
def dur_neg  : duration_expr std_sp := -one_second
def dur_sub  : duration_expr std_sp := one_second -ᵥ 0 -ᵥ one_second
def dur_time  : duration_expr std_sp := launch_time -ᵥ launch_time
def dur_smul  : duration_expr std_sp := (3:ℚ/-again, ℚ is K, the configured scalar field-/)•one_second

def time_lit : time_expr std_sp := [launch_time.value]
def time_var : time_expr std_sp := time_expr.var ⟨⟨"time"⟩⟩
def time_add : time_expr std_sp := one_second +ᵥ launch_time -- need to add reverse notation

--Test Transforms next
def transform_lit :
  transform_expr std_sp mission_space :=  [(std_sp.value.time_tr mission_space.value)]
def transform_var : transform_expr std_sp mission_space := transform_expr.var ⟨⟨"tr"⟩⟩

--belongs with time and duration tests, but...
--also, these cannot be deeply embedded
--required to evaluate the point or vector operand
--needs notation?
def dur_apply : duration_expr mission_space :=
  duration_expr.apply_duration_lit transform_lit one_second.value
def time_apply : time_expr mission_space :=
  time_expr.apply_time_lit transform_lit launch_time.value

--used for compose
def mission_to_std :
  transform_expr mission_space std_sp
  :=
  [(mission_space.value.time_tr std_sp.value)]
def std_to_mission := transform_lit
--compose result (trans used by mathlib)
--compose not deeply embedded, same limitation as apply
def std_to_std : transform_expr std_sp std_sp := std_to_mission.trans mission_to_std

--inverse
--inverse not deeply embedded, same limitation as apply
def mission_to_std' :
  transform_expr mission_space std_sp := std_to_mission⁻¹

--a few type errors

--adding wrong spaces/frames
def mission_dur : duration_expr mission_space := [(mk_duration mission_space.value 1)]
def wrong_spaces := mission_dur +ᵥ dur_lit --dur_lit in standard space

--bad apply
def bad_apply := duration_expr.apply_duration_lit mission_to_std dur_lit --dur_lit not in mission space

--bad compose
def bad_compose := std_to_mission.trans std_to_mission

--adding points
def point_add := launch_time +ᵥ launch_time


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

universes u_6 u_7 u_8 l u_1 u_2 u_3 u_4 u_5

namespace Mathlib

/-!
# Linear isometries

In this file we define `linear_isometry R E F` (notation: `E →ₗᵢ[R] F`) to be a linear isometric
embedding of `E` into `F` and `linear_isometry_equiv` (notation: `E ≃ₗᵢ[R] F`) to be a linear
isometric equivalence between `E` and `F`.

We also prove some trivial lemmas and provide convenience constructors.
-/

/-- An `R`-linear isometric embedding of one normed `R`-module into another. -/
structure linear_isometry (R : Type u_6) (E : Type u_7) (F : Type u_8) [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F]
extends linear_map R E F
where
  norm_map' : ∀ (x : E), norm (coe_fn _to_linear_map x) = norm x

namespace linear_isometry

protected instance has_coe_to_fun {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] : has_coe_to_fun (linear_isometry R E F) :=
  has_coe_to_fun.mk (fun (f : linear_isometry R E F) => E → F)
    fun (f : linear_isometry R E F) => linear_map.to_fun (to_linear_map f)

@[simp] theorem coe_to_linear_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : ⇑(to_linear_map f) = ⇑f :=
  rfl

theorem to_linear_map_injective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] : function.injective to_linear_map := sorry

theorem coe_fn_injective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] : function.injective fun (f : linear_isometry R E F) (x : E) => coe_fn f x :=
  function.injective.comp linear_map.coe_injective to_linear_map_injective

theorem ext {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] {f : linear_isometry R E F} {g : linear_isometry R E F} (h : ∀ (x : E), coe_fn f x = coe_fn g x) : f = g :=
  coe_fn_injective (funext h)

@[simp] theorem map_zero {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : coe_fn f 0 = 0 :=
  linear_map.map_zero (to_linear_map f)

@[simp] theorem map_add {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (x : E) (y : E) : coe_fn f (x + y) = coe_fn f x + coe_fn f y :=
  linear_map.map_add (to_linear_map f) x y

@[simp] theorem map_sub {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (x : E) (y : E) : coe_fn f (x - y) = coe_fn f x - coe_fn f y :=
  linear_map.map_sub (to_linear_map f) x y

@[simp] theorem map_smul {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (c : R) (x : E) : coe_fn f (c • x) = c • coe_fn f x :=
  linear_map.map_smul (to_linear_map f) c x

@[simp] theorem norm_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (x : E) : norm (coe_fn f x) = norm x :=
  norm_map' f x

@[simp] theorem nnnorm_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (x : E) : nnnorm (coe_fn f x) = nnnorm x :=
  nnreal.eq (norm_map f x)

protected theorem isometry {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : isometry ⇑f :=
  add_monoid_hom.isometry_of_norm (linear_map.to_add_monoid_hom (to_linear_map f)) (norm_map f)

@[simp] theorem dist_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (x : E) (y : E) : dist (coe_fn f x) (coe_fn f y) = dist x y :=
  isometry.dist_eq (linear_isometry.isometry f) x y

@[simp] theorem edist_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (x : E) (y : E) : edist (coe_fn f x) (coe_fn f y) = edist x y :=
  isometry.edist_eq (linear_isometry.isometry f) x y

protected theorem injective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : function.injective ⇑f :=
  isometry.injective (linear_isometry.isometry f)

theorem map_eq_iff {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) {x : E} {y : E} : coe_fn f x = coe_fn f y ↔ x = y :=
  function.injective.eq_iff (linear_isometry.injective f)

theorem map_ne {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) {x : E} {y : E} (h : x ≠ y) : coe_fn f x ≠ coe_fn f y :=
  function.injective.ne (linear_isometry.injective f) h

protected theorem lipschitz {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : lipschitz_with 1 ⇑f :=
  isometry.lipschitz (linear_isometry.isometry f)

protected theorem antilipschitz {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : antilipschitz_with 1 ⇑f :=
  isometry.antilipschitz (linear_isometry.isometry f)

protected theorem continuous {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : continuous ⇑f :=
  isometry.continuous (linear_isometry.isometry f)

theorem ediam_image {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (s : set E) : emetric.diam (⇑f '' s) = emetric.diam s :=
  isometry.ediam_image (linear_isometry.isometry f) s

theorem ediam_range {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : emetric.diam (set.range ⇑f) = emetric.diam set.univ :=
  isometry.ediam_range (linear_isometry.isometry f)

theorem diam_image {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) (s : set E) : metric.diam (⇑f '' s) = metric.diam s :=
  isometry.diam_image (linear_isometry.isometry f) s

theorem diam_range {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : metric.diam (set.range ⇑f) = metric.diam set.univ :=
  isometry.diam_range (linear_isometry.isometry f)

/-- Interpret a linear isometry as a continuous linear map. -/
def to_continuous_linear_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : continuous_linear_map R E F :=
  continuous_linear_map.mk (to_linear_map f)

@[simp] theorem coe_to_continuous_linear_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : ⇑(to_continuous_linear_map f) = ⇑f :=
  rfl

@[simp] theorem comp_continuous_iff {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) {α : Type u_4} [topological_space α] {g : α → E} : continuous (⇑f ∘ g) ↔ continuous g := sorry

/-- The identity linear isometry. -/
def id {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : linear_isometry R E E :=
  mk linear_map.id sorry

@[simp] theorem coe_id {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : ⇑id = ⇑id :=
  rfl

protected instance inhabited {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : Inhabited (linear_isometry R E E) :=
  { default := id }

/-- Composition of linear isometries. -/
def comp {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} [semiring R] [normed_group E] [normed_group F] [normed_group G] [semimodule R E] [semimodule R F] [semimodule R G] (g : linear_isometry R F G) (f : linear_isometry R E F) : linear_isometry R E G :=
  mk (linear_map.comp (to_linear_map g) (to_linear_map f)) sorry

@[simp] theorem coe_comp {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} [semiring R] [normed_group E] [normed_group F] [normed_group G] [semimodule R E] [semimodule R F] [semimodule R G] (g : linear_isometry R F G) (f : linear_isometry R E F) : ⇑(comp g f) = ⇑g ∘ ⇑f :=
  rfl

@[simp] theorem id_comp {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : comp id f = f :=
  ext fun (x : E) => rfl

@[simp] theorem comp_id {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (f : linear_isometry R E F) : comp f id = f :=
  ext fun (x : E) => rfl

theorem comp_assoc {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} {G' : Type u_5} [semiring R] [normed_group E] [normed_group F] [normed_group G] [normed_group G'] [semimodule R E] [semimodule R F] [semimodule R G] [semimodule R G'] (f : linear_isometry R G G') (g : linear_isometry R F G) (h : linear_isometry R E F) : comp (comp f g) h = comp f (comp g h) :=
  rfl

protected instance monoid {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : monoid (linear_isometry R E E) :=
  monoid.mk comp comp_assoc id id_comp comp_id

@[simp] theorem coe_one {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : ⇑1 = ⇑id :=
  rfl

@[simp] theorem coe_mul {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] (f : linear_isometry R E E) (g : linear_isometry R E E) : ⇑(f * g) = ⇑f ∘ ⇑g :=
  rfl

end linear_isometry

/-- A linear isometric equivalence between two normed vector spaces. -/
structure linear_isometry_equiv (R : Type u_6) (E : Type u_7) (F : Type u_8) [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F]
extends linear_equiv R E F
where
  norm_map' : ∀ (x : E), norm (coe_fn _to_linear_equiv x) = norm x

namespace linear_isometry_equiv

protected instance has_coe_to_fun {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] : has_coe_to_fun (linear_isometry_equiv R E F) :=
  has_coe_to_fun.mk (fun (f : linear_isometry_equiv R E F) => E → F)
    fun (f : linear_isometry_equiv R E F) => linear_equiv.to_fun (to_linear_equiv f)

@[simp] theorem coe_mk {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_equiv R E F) (he : ∀ (x : E), norm (coe_fn e x) = norm x) : ⇑(mk e he) = ⇑e :=
  rfl

@[simp] theorem coe_to_linear_equiv {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : ⇑(to_linear_equiv e) = ⇑e :=
  rfl

theorem to_linear_equiv_injective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] : function.injective to_linear_equiv := sorry

theorem ext {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] {e : linear_isometry_equiv R E F} {e' : linear_isometry_equiv R E F} (h : ∀ (x : E), coe_fn e x = coe_fn e' x) : e = e' :=
  to_linear_equiv_injective (linear_equiv.ext h)

/-- Construct a `linear_isometry_equiv` from a `linear_equiv` and two inequalities:
`∀ x, ∥e x∥ ≤ ∥x∥` and `∀ y, ∥e.symm y∥ ≤ ∥y∥`. -/
def of_bounds {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_equiv R E F) (h₁ : ∀ (x : E), norm (coe_fn e x) ≤ norm x) (h₂ : ∀ (y : F), norm (coe_fn (linear_equiv.symm e) y) ≤ norm y) : linear_isometry_equiv R E F :=
  mk e sorry

@[simp] theorem norm_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) : norm (coe_fn e x) = norm x :=
  norm_map' e x

/-- Reinterpret a `linear_isometry_equiv` as a `linear_isometry`. -/
def to_linear_isometry {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : linear_isometry R E F :=
  linear_isometry.mk (↑(to_linear_equiv e)) (norm_map' e)

protected theorem isometry {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : isometry ⇑e :=
  linear_isometry.isometry (to_linear_isometry e)

/-- Reinterpret a `linear_isometry_equiv` as an `isometric`. -/
def to_isometric {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : E ≃ᵢ F :=
  isometric.mk (linear_equiv.to_equiv (to_linear_equiv e)) (linear_isometry_equiv.isometry e)

protected theorem continuous {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : continuous ⇑e :=
  isometry.continuous (linear_isometry_equiv.isometry e)

/-- Identity map as a `linear_isometry_equiv`. -/
def refl (R : Type u_1) (E : Type u_2) [semiring R] [normed_group E] [semimodule R E] : linear_isometry_equiv R E E :=
  mk (linear_equiv.refl R E) sorry

protected instance inhabited {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : Inhabited (linear_isometry_equiv R E E) :=
  { default := refl R E }

@[simp] theorem coe_refl {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : ⇑(refl R E) = id :=
  rfl

/-- The inverse `linear_isometry_equiv`. -/
def symm {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : linear_isometry_equiv R F E :=
  mk (linear_equiv.symm (to_linear_equiv e)) sorry

@[simp] theorem apply_symm_apply {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : F) : coe_fn e (coe_fn (symm e) x) = x :=
  linear_equiv.apply_symm_apply (to_linear_equiv e) x

@[simp] theorem symm_apply_apply {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) : coe_fn (symm e) (coe_fn e x) = x :=
  linear_equiv.symm_apply_apply (to_linear_equiv e) x

@[simp] theorem map_eq_zero_iff {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) {x : E} : coe_fn e x = 0 ↔ x = 0 :=
  linear_equiv.map_eq_zero_iff (to_linear_equiv e)

@[simp] theorem symm_symm {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : symm (symm e) = e :=
  ext fun (x : E) => rfl

@[simp] theorem coe_symm_to_linear_equiv {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : ⇑(linear_equiv.symm (to_linear_equiv e)) = ⇑(symm e) :=
  rfl

/-- Composition of `linear_isometry_equiv`s as a `linear_isometry_equiv`. -/
def trans {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} [semiring R] [normed_group E] [normed_group F] [normed_group G] [semimodule R E] [semimodule R F] [semimodule R G] (e : linear_isometry_equiv R E F) (e' : linear_isometry_equiv R F G) : linear_isometry_equiv R E G :=
  mk (linear_equiv.trans (to_linear_equiv e) (to_linear_equiv e')) sorry

@[simp] theorem coe_trans {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} [semiring R] [normed_group E] [normed_group F] [normed_group G] [semimodule R E] [semimodule R F] [semimodule R G] (e₁ : linear_isometry_equiv R E F) (e₂ : linear_isometry_equiv R F G) : ⇑(trans e₁ e₂) = ⇑e₂ ∘ ⇑e₁ :=
  rfl

@[simp] theorem trans_refl {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : trans e (refl R F) = e :=
  ext fun (x : E) => rfl

@[simp] theorem refl_trans {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : trans (refl R E) e = e :=
  ext fun (x : E) => rfl

@[simp] theorem trans_symm {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : trans e (symm e) = refl R E :=
  ext (symm_apply_apply e)

@[simp] theorem symm_trans {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : trans (symm e) e = refl R F :=
  ext (apply_symm_apply e)

@[simp] theorem coe_symm_trans {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} [semiring R] [normed_group E] [normed_group F] [normed_group G] [semimodule R E] [semimodule R F] [semimodule R G] (e₁ : linear_isometry_equiv R E F) (e₂ : linear_isometry_equiv R F G) : ⇑(symm (trans e₁ e₂)) = ⇑(symm e₁) ∘ ⇑(symm e₂) :=
  rfl

theorem trans_assoc {R : Type u_1} {E : Type u_2} {F : Type u_3} {G : Type u_4} {G' : Type u_5} [semiring R] [normed_group E] [normed_group F] [normed_group G] [normed_group G'] [semimodule R E] [semimodule R F] [semimodule R G] [semimodule R G'] (eEF : linear_isometry_equiv R E F) (eFG : linear_isometry_equiv R F G) (eGG' : linear_isometry_equiv R G G') : trans eEF (trans eFG eGG') = trans (trans eEF eFG) eGG' :=
  rfl

protected instance group {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : group (linear_isometry_equiv R E E) :=
  group.mk (fun (e₁ e₂ : linear_isometry_equiv R E E) => trans e₂ e₁) sorry (refl R E) trans_refl refl_trans symm
    (div_inv_monoid.div._default (fun (e₁ e₂ : linear_isometry_equiv R E E) => trans e₂ e₁) sorry (refl R E) trans_refl
      refl_trans symm)
    trans_symm

@[simp] theorem coe_one {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] : ⇑1 = id :=
  rfl

@[simp] theorem coe_mul {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] (e : linear_isometry_equiv R E E) (e' : linear_isometry_equiv R E E) : ⇑(e * e') = ⇑e ∘ ⇑e' :=
  rfl

@[simp] theorem coe_inv {R : Type u_1} {E : Type u_2} [semiring R] [normed_group E] [semimodule R E] (e : linear_isometry_equiv R E E) : ⇑(e⁻¹) = ⇑(symm e) :=
  rfl

/-- Reinterpret a `linear_isometry_equiv` as a `continuous_linear_equiv`. -/
def to_continuous_linear_equiv {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : continuous_linear_equiv R E F :=
  continuous_linear_equiv.mk (to_linear_equiv e)

@[simp] theorem map_zero {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : coe_fn e 0 = 0 :=
  linear_equiv.map_zero (to_linear_equiv e)

@[simp] theorem map_add {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) (y : E) : coe_fn e (x + y) = coe_fn e x + coe_fn e y :=
  linear_equiv.map_add (to_linear_equiv e) x y

@[simp] theorem map_sub {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) (y : E) : coe_fn e (x - y) = coe_fn e x - coe_fn e y :=
  linear_equiv.map_sub (to_linear_equiv e) x y

@[simp] theorem map_smul {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (c : R) (x : E) : coe_fn e (c • x) = c • coe_fn e x :=
  linear_equiv.map_smul (to_linear_equiv e) c x

@[simp] theorem nnnorm_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) : nnnorm (coe_fn e x) = nnnorm x :=
  linear_isometry.nnnorm_map (to_linear_isometry e) x

@[simp] theorem dist_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) (y : E) : dist (coe_fn e x) (coe_fn e y) = dist x y :=
  linear_isometry.dist_map (to_linear_isometry e) x y

@[simp] theorem edist_map {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (x : E) (y : E) : edist (coe_fn e x) (coe_fn e y) = edist x y :=
  linear_isometry.edist_map (to_linear_isometry e) x y

protected theorem bijective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : function.bijective ⇑e :=
  linear_equiv.bijective (to_linear_equiv e)

protected theorem injective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : function.injective ⇑e :=
  linear_equiv.injective (to_linear_equiv e)

protected theorem surjective {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : function.surjective ⇑e :=
  linear_equiv.surjective (to_linear_equiv e)

theorem map_eq_iff {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) {x : E} {y : E} : coe_fn e x = coe_fn e y ↔ x = y :=
  function.injective.eq_iff (linear_isometry_equiv.injective e)

theorem map_ne {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) {x : E} {y : E} (h : x ≠ y) : coe_fn e x ≠ coe_fn e y :=
  function.injective.ne (linear_isometry_equiv.injective e) h

protected theorem lipschitz {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : lipschitz_with 1 ⇑e :=
  isometry.lipschitz (linear_isometry_equiv.isometry e)

protected theorem antilipschitz {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) : antilipschitz_with 1 ⇑e :=
  isometry.antilipschitz (linear_isometry_equiv.isometry e)

theorem ediam_image {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (s : set E) : emetric.diam (⇑e '' s) = emetric.diam s :=
  isometry.ediam_image (linear_isometry_equiv.isometry e) s

theorem diam_image {R : Type u_1} {E : Type u_2} {F : Type u_3} [semiring R] [normed_group E] [normed_group F] [semimodule R E] [semimodule R F] (e : linear_isometry_equiv R E F) (s : set E) : metric.diam (⇑e '' s) = metric.diam s :=
  isometry.diam_image (linear_isometry_equiv.isometry e) s