/-
Copyright (c) 2021 Oliver Nash. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Oliver Nash
-/
import algebra.lie.basic
import ring_theory.noetherian

/-!
# Lie subalgebras

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

This file defines Lie subalgebras of a Lie algebra and provides basic related definitions and
results.

## Main definitions

  * `lie_subalgebra`
  * `lie_subalgebra.incl`
  * `lie_subalgebra.map`
  * `lie_hom.range`
  * `lie_equiv.of_injective`
  * `lie_equiv.of_eq`
  * `lie_equiv.of_subalgebra`
  * `lie_equiv.of_subalgebras`

## Tags

lie algebra, lie subalgebra
-/

universes u v w w₁ w₂

section lie_subalgebra

variables (R : Type u) (L : Type v) [comm_ring R] [lie_ring L] [lie_algebra R L]

/-- A Lie subalgebra of a Lie algebra is submodule that is closed under the Lie bracket.
This is a sufficient condition for the subset itself to form a Lie algebra. -/
structure lie_subalgebra extends submodule R L :=
(lie_mem' : ∀ {x y}, x ∈ carrier → y ∈ carrier → ⁅x, y⁆ ∈ carrier)

attribute [nolint doc_blame] lie_subalgebra.to_submodule

/-- The zero algebra is a subalgebra of any Lie algebra. -/
instance : has_zero (lie_subalgebra R L) :=
⟨{ lie_mem' := λ x y hx hy, by { rw [((submodule.mem_bot R).1 hx), zero_lie],
                                exact submodule.zero_mem (0 : submodule R L), },
   ..(0 : submodule R L) }⟩

instance : inhabited (lie_subalgebra R L) := ⟨0⟩
instance : has_coe (lie_subalgebra R L) (submodule R L) := ⟨lie_subalgebra.to_submodule⟩

namespace lie_subalgebra

instance : set_like (lie_subalgebra R L) L :=
{ coe := λ L', L',
  coe_injective' := λ L' L'' h, by { rcases L' with ⟨⟨⟩⟩, rcases L'' with ⟨⟨⟩⟩, congr' } }

instance : add_subgroup_class (lie_subalgebra R L) L :=
{ add_mem := λ L' _ _, L'.add_mem',
  zero_mem := λ L', L'.zero_mem',
  neg_mem := λ L' x hx, show -x ∈ (L' : submodule R L), from neg_mem hx }

/-- A Lie subalgebra forms a new Lie ring. -/
instance (L' : lie_subalgebra R L) : lie_ring L' :=
{ bracket      := λ x y, ⟨⁅x.val, y.val⁆, L'.lie_mem' x.property y.property⟩,
  lie_add      := by { intros, apply set_coe.ext, apply lie_add, },
  add_lie      := by { intros, apply set_coe.ext, apply add_lie, },
  lie_self     := by { intros, apply set_coe.ext, apply lie_self, },
  leibniz_lie  := by { intros, apply set_coe.ext, apply leibniz_lie, } }

section

variables {R₁ : Type*} [semiring R₁]

/-- A Lie subalgebra inherits module structures from `L`. -/
instance [has_smul R₁ R] [module R₁ L] [is_scalar_tower R₁ R L]
  (L' : lie_subalgebra R L) : module R₁ L' :=
L'.to_submodule.module'

instance [has_smul R₁ R] [has_smul R₁ᵐᵒᵖ R] [module R₁ L] [module R₁ᵐᵒᵖ L]
  [is_scalar_tower R₁ R L] [is_scalar_tower R₁ᵐᵒᵖ R L] [is_central_scalar R₁ L]
  (L' : lie_subalgebra R L) : is_central_scalar R₁ L' :=
L'.to_submodule.is_central_scalar

instance [has_smul R₁ R] [module R₁ L] [is_scalar_tower R₁ R L]
  (L' : lie_subalgebra R L) : is_scalar_tower R₁ R L' :=
L'.to_submodule.is_scalar_tower

instance (L' : lie_subalgebra R L) [is_noetherian R L] : is_noetherian R L' :=
is_noetherian_submodule' ↑L'

end

/-- A Lie subalgebra forms a new Lie algebra. -/
instance (L' : lie_subalgebra R L) : lie_algebra R L' :=
{ lie_smul := by { intros, apply set_coe.ext, apply lie_smul } }

variables {R L} (L' : lie_subalgebra R L)

@[simp] protected lemma zero_mem : (0 : L) ∈ L' := zero_mem L'
protected lemma add_mem {x y : L} : x ∈ L' → y ∈ L' → (x + y : L) ∈ L' := add_mem
protected lemma sub_mem {x y : L} : x ∈ L' → y ∈ L' → (x - y : L) ∈ L' := sub_mem

lemma smul_mem (t : R) {x : L} (h : x ∈ L') : t • x ∈ L' := (L' : submodule R L).smul_mem t h

lemma lie_mem {x y : L} (hx : x ∈ L') (hy : y ∈ L') : (⁅x, y⁆ : L) ∈ L' := L'.lie_mem' hx hy

@[simp] lemma mem_carrier {x : L} : x ∈ L'.carrier ↔ x ∈ (L' : set L) := iff.rfl

@[simp] lemma mem_mk_iff (S : set L) (h₁ h₂ h₃ h₄) {x : L} :
  x ∈ (⟨⟨S, h₁, h₂, h₃⟩, h₄⟩ : lie_subalgebra R L) ↔ x ∈ S :=
iff.rfl

@[simp] lemma mem_coe_submodule {x : L} : x ∈ (L' : submodule R L) ↔ x ∈ L' := iff.rfl

lemma mem_coe {x : L} : x ∈ (L' : set L) ↔ x ∈ L' := iff.rfl

@[simp, norm_cast] lemma coe_bracket (x y : L') : (↑⁅x, y⁆ : L) = ⁅(↑x : L), ↑y⁆ := rfl

lemma ext_iff (x y : L') : x = y ↔ (x : L) = y := subtype.ext_iff

lemma coe_zero_iff_zero (x : L') : (x : L) = 0 ↔ x = 0 := (ext_iff L' x 0).symm

@[ext] lemma ext (L₁' L₂' : lie_subalgebra R L) (h : ∀ x, x ∈ L₁' ↔ x ∈ L₂') :
  L₁' = L₂' :=
set_like.ext h

lemma ext_iff' (L₁' L₂' : lie_subalgebra R L) : L₁' = L₂' ↔ ∀ x, x ∈ L₁' ↔ x ∈ L₂' :=
set_like.ext_iff

@[simp] lemma mk_coe (S : set L) (h₁ h₂ h₃ h₄) :
  ((⟨⟨S, h₁, h₂, h₃⟩, h₄⟩ : lie_subalgebra R L) : set L) = S := rfl

@[simp] lemma coe_to_submodule_mk (p : submodule R L) (h) :
  (({lie_mem' := h, ..p} : lie_subalgebra R L) : submodule R L) = p :=
by { cases p, refl, }

lemma coe_injective : function.injective (coe : lie_subalgebra R L → set L) :=
set_like.coe_injective

@[norm_cast] theorem coe_set_eq (L₁' L₂' : lie_subalgebra R L) :
  (L₁' : set L) = L₂' ↔ L₁' = L₂' := set_like.coe_set_eq

lemma to_submodule_injective :
  function.injective (coe : lie_subalgebra R L → submodule R L) :=
λ L₁' L₂' h, by { rw set_like.ext'_iff at h, rw ← coe_set_eq, exact h, }

@[simp] lemma coe_to_submodule_eq_iff (L₁' L₂' : lie_subalgebra R L) :
  (L₁' : submodule R L) = (L₂' : submodule R L) ↔ L₁' = L₂' :=
to_submodule_injective.eq_iff

@[norm_cast]
lemma coe_to_submodule : ((L' : submodule R L) : set L) = L' := rfl

section lie_module

variables {M : Type w} [add_comm_group M] [lie_ring_module L M]
variables {N : Type w₁} [add_comm_group N] [lie_ring_module L N] [module R N] [lie_module R L N]

/-- Given a Lie algebra `L` containing a Lie subalgebra `L' ⊆ L`, together with a Lie ring module
`M` of `L`, we may regard `M` as a Lie ring module of `L'` by restriction. -/
instance : lie_ring_module L' M :=
{ bracket     := λ x m, ⁅(x : L), m⁆,
  add_lie     := λ x y m, add_lie x y m,
  lie_add     := λ x y m, lie_add x y m,
  leibniz_lie := λ x y m, leibniz_lie x y m, }

@[simp] lemma coe_bracket_of_module (x : L') (m : M) : ⁅x, m⁆ = ⁅(x : L), m⁆ := rfl

variables [module R M] [lie_module R L M]

/-- Given a Lie algebra `L` containing a Lie subalgebra `L' ⊆ L`, together with a Lie module `M` of
`L`, we may regard `M` as a Lie module of `L'` by restriction. -/
instance : lie_module R L' M :=
{ smul_lie := λ t x m, by simp only [coe_bracket_of_module, smul_lie, submodule.coe_smul_of_tower],
  lie_smul := λ t x m, by simp only [coe_bracket_of_module, lie_smul], }

/-- An `L`-equivariant map of Lie modules `M → N` is `L'`-equivariant for any Lie subalgebra
`L' ⊆ L`. -/
def _root_.lie_module_hom.restrict_lie (f : M →ₗ⁅R,L⁆ N) (L' : lie_subalgebra R L) : M →ₗ⁅R,L'⁆ N :=
{ map_lie' := λ x m, f.map_lie ↑x m,
  .. (f : M →ₗ[R] N)}

@[simp] lemma _root_.lie_module_hom.coe_restrict_lie (f : M →ₗ⁅R,L⁆ N) :
  ⇑(f.restrict_lie L') = f :=
rfl

end lie_module

/-- The embedding of a Lie subalgebra into the ambient space as a morphism of Lie algebras. -/
def incl : L' →ₗ⁅R⁆ L :=
{ map_lie' := λ x y, by { simp only [linear_map.to_fun_eq_coe, submodule.subtype_apply], refl, },
  .. (L' : submodule R L).subtype, }

@[simp] lemma coe_incl : ⇑L'.incl = coe := rfl

/-- The embedding of a Lie subalgebra into the ambient space as a morphism of Lie modules. -/
def incl' : L' →ₗ⁅R,L'⁆ L :=
{ map_lie' := λ x y, by simp only [coe_bracket_of_module, linear_map.to_fun_eq_coe,
    submodule.subtype_apply, coe_bracket],
  .. (L' : submodule R L).subtype, }

@[simp] lemma coe_incl' : ⇑L'.incl' = coe := rfl

end lie_subalgebra

variables {R L} {L₂ : Type w} [lie_ring L₂] [lie_algebra R L₂]
variables (f : L →ₗ⁅R⁆ L₂)

namespace lie_hom

/-- The range of a morphism of Lie algebras is a Lie subalgebra. -/
def range : lie_subalgebra R L₂ :=
{ lie_mem' := λ x y,
    show x ∈ f.to_linear_map.range → y ∈ f.to_linear_map.range → ⁅x, y⁆ ∈ f.to_linear_map.range,
    by { repeat { rw linear_map.mem_range }, rintros ⟨x', hx⟩ ⟨y', hy⟩, refine ⟨⁅x', y'⁆, _⟩,
         rw [←hx, ←hy], change f ⁅x', y'⁆ = ⁅f x', f y'⁆, rw map_lie, },
  ..(f : L →ₗ[R] L₂).range }

@[simp] lemma range_coe : (f.range : set L₂) = set.range f :=
linear_map.range_coe ↑f

@[simp] lemma mem_range (x : L₂) : x ∈ f.range ↔ ∃ (y : L), f y = x := linear_map.mem_range

lemma mem_range_self (x : L) : f x ∈ f.range := linear_map.mem_range_self f x

/-- We can restrict a morphism to a (surjective) map to its range. -/
def range_restrict : L →ₗ⁅R⁆ f.range :=
{ map_lie' := λ x y, by { apply subtype.ext, exact f.map_lie x y, },
  ..(f : L →ₗ[R] L₂).range_restrict, }

@[simp] lemma range_restrict_apply (x : L) : f.range_restrict x = ⟨f x, f.mem_range_self x⟩ := rfl

lemma surjective_range_restrict : function.surjective (f.range_restrict) :=
begin
  rintros ⟨y, hy⟩,
  erw mem_range at hy, obtain ⟨x, rfl⟩ := hy,
  use x,
  simp only [subtype.mk_eq_mk, range_restrict_apply],
end

/-- A Lie algebra is equivalent to its range under an injective Lie algebra morphism. -/
noncomputable def equiv_range_of_injective (h : function.injective f) : L ≃ₗ⁅R⁆ f.range :=
lie_equiv.of_bijective f.range_restrict ⟨λ x y hxy,
begin
  simp only [subtype.mk_eq_mk, range_restrict_apply] at hxy,
  exact h hxy,
end, f.surjective_range_restrict⟩

@[simp] lemma equiv_range_of_injective_apply (h : function.injective f) (x : L) :
  f.equiv_range_of_injective h x = ⟨f x, mem_range_self f x⟩ :=
rfl

end lie_hom

lemma submodule.exists_lie_subalgebra_coe_eq_iff (p : submodule R L) :
  (∃ (K : lie_subalgebra R L), ↑K = p) ↔ ∀ (x y : L), x ∈ p → y ∈ p → ⁅x, y⁆ ∈ p :=
begin
  split,
  { rintros ⟨K, rfl⟩ _ _, exact K.lie_mem', },
  { intros h, use { lie_mem' := h, ..p }, exact lie_subalgebra.coe_to_submodule_mk p _, },
end

namespace lie_subalgebra

variables (K K' : lie_subalgebra R L) (K₂ : lie_subalgebra R L₂)

@[simp] lemma incl_range : K.incl.range = K :=
by { rw ← coe_to_submodule_eq_iff, exact (K : submodule R L).range_subtype, }

/-- The image of a Lie subalgebra under a Lie algebra morphism is a Lie subalgebra of the
codomain. -/
def map : lie_subalgebra R L₂ :=
{ lie_mem' := λ x y hx hy, by
  { erw submodule.mem_map at hx, rcases hx with ⟨x', hx', hx⟩, rw ←hx,
    erw submodule.mem_map at hy, rcases hy with ⟨y', hy', hy⟩, rw ←hy,
    erw submodule.mem_map,
    exact ⟨⁅x', y'⁆, K.lie_mem hx' hy', f.map_lie x' y'⟩, },
..((K : submodule R L).map (f : L →ₗ[R] L₂)) }

@[simp] lemma mem_map (x : L₂) : x ∈ K.map f ↔ ∃ (y : L), y ∈ K ∧ f y = x := submodule.mem_map

-- TODO Rename and state for homs instead of equivs.
@[simp] lemma mem_map_submodule (e : L ≃ₗ⁅R⁆ L₂) (x : L₂) :
  x ∈ K.map (e : L →ₗ⁅R⁆ L₂) ↔ x ∈ (K : submodule R L).map (e : L →ₗ[R] L₂) :=
iff.rfl

/-- The preimage of a Lie subalgebra under a Lie algebra morphism is a Lie subalgebra of the
domain. -/
def comap : lie_subalgebra R L :=
{ lie_mem' := λ x y hx hy, by
    { suffices : ⁅f x, f y⁆ ∈ K₂, by { simp [this], }, exact K₂.lie_mem hx hy, },
  ..((K₂ : submodule R L₂).comap (f : L →ₗ[R] L₂)), }

section lattice_structure

open set

instance : partial_order (lie_subalgebra R L) :=
{ le := λ N N', ∀ ⦃x⦄, x ∈ N → x ∈ N', -- Overriding `le` like this gives a better defeq.
  ..partial_order.lift (coe : lie_subalgebra R L → set L) coe_injective }

lemma le_def : K ≤ K' ↔ (K : set L) ⊆ K' := iff.rfl

@[simp, norm_cast] lemma coe_submodule_le_coe_submodule : (K : submodule R L) ≤ K' ↔ K ≤ K' :=
iff.rfl

instance : has_bot (lie_subalgebra R L) := ⟨0⟩

@[simp] lemma bot_coe : ((⊥ : lie_subalgebra R L) : set L) = {0} := rfl

@[simp] lemma bot_coe_submodule : ((⊥ : lie_subalgebra R L) : submodule R L) = ⊥ := rfl

@[simp] lemma mem_bot (x : L) : x ∈ (⊥ : lie_subalgebra R L) ↔ x = 0 := mem_singleton_iff

instance : has_top (lie_subalgebra R L) :=
⟨{ lie_mem' := λ x y hx hy, mem_univ ⁅x, y⁆,
   ..(⊤ : submodule R L) }⟩

@[simp] lemma top_coe : ((⊤ : lie_subalgebra R L) : set L) = univ := rfl

@[simp] lemma top_coe_submodule : ((⊤ : lie_subalgebra R L) : submodule R L) = ⊤ := rfl

@[simp] lemma mem_top (x : L) : x ∈ (⊤ : lie_subalgebra R L) := mem_univ x

lemma _root_.lie_hom.range_eq_map : f.range = map f ⊤ :=
by { ext, simp }

instance : has_inf (lie_subalgebra R L) :=
⟨λ K K', { lie_mem' := λ x y hx hy, mem_inter (K.lie_mem hx.1 hy.1) (K'.lie_mem hx.2 hy.2),
            ..(K ⊓ K' : submodule R L) }⟩

instance : has_Inf (lie_subalgebra R L) :=
⟨λ S, { lie_mem' := λ x y hx hy, by
        { simp only [submodule.mem_carrier, mem_Inter, submodule.Inf_coe, mem_set_of_eq,
            forall_apply_eq_imp_iff₂, exists_imp_distrib] at *,
          intros K hK, exact K.lie_mem (hx K hK) (hy K hK), },
        ..Inf {(s : submodule R L) | s ∈ S} }⟩

@[simp] theorem inf_coe : (↑(K ⊓ K') : set L) = K ∩ K' := rfl

@[simp] lemma Inf_coe_to_submodule (S : set (lie_subalgebra R L)) :
  (↑(Inf S) : submodule R L) = Inf {(s : submodule R L) | s ∈ S} := rfl

@[simp] lemma Inf_coe (S : set (lie_subalgebra R L)) : (↑(Inf S) : set L) = ⋂ s ∈ S, (s : set L) :=
begin
  rw [← coe_to_submodule, Inf_coe_to_submodule, submodule.Inf_coe],
  ext x,
  simpa only [mem_Inter, mem_set_of_eq, forall_apply_eq_imp_iff₂, exists_imp_distrib],
end

lemma Inf_glb (S : set (lie_subalgebra R L)) : is_glb S (Inf S) :=
begin
  have h : ∀ (K K' : lie_subalgebra R L), (K : set L) ≤ K' ↔ K ≤ K', { intros, exact iff.rfl, },
  apply is_glb.of_image h,
  simp only [Inf_coe],
  exact is_glb_binfi
end

/-- The set of Lie subalgebras of a Lie algebra form a complete lattice.

We provide explicit values for the fields `bot`, `top`, `inf` to get more convenient definitions
than we would otherwise obtain from `complete_lattice_of_Inf`. -/
instance : complete_lattice (lie_subalgebra R L) :=
{ bot          := ⊥,
  bot_le       := λ N _ h, by { rw mem_bot at h, rw h, exact N.zero_mem', },
  top          := ⊤,
  le_top       := λ _ _ _, trivial,
  inf          := (⊓),
  le_inf       := λ N₁ N₂ N₃ h₁₂ h₁₃ m hm, ⟨h₁₂ hm, h₁₃ hm⟩,
  inf_le_left  := λ _ _ _, and.left,
  inf_le_right := λ _ _ _, and.right,
  ..complete_lattice_of_Inf _ Inf_glb }

instance : add_comm_monoid (lie_subalgebra R L) :=
{ add       := (⊔),
  add_assoc := λ _ _ _, sup_assoc,
  zero      := ⊥,
  zero_add  := λ _, bot_sup_eq,
  add_zero  := λ _, sup_bot_eq,
  add_comm  := λ _ _, sup_comm, }

instance : canonically_ordered_add_monoid (lie_subalgebra R L) :=
{ add_le_add_left := λ a b, sup_le_sup_left,
  exists_add_of_le := λ a b h, ⟨b, (sup_eq_right.2 h).symm⟩,
  le_self_add := λ a b, le_sup_left,
  ..lie_subalgebra.add_comm_monoid,
  ..lie_subalgebra.complete_lattice }

@[simp] lemma add_eq_sup : K + K' = K ⊔ K' := rfl

@[norm_cast, simp] lemma inf_coe_to_submodule :
  (↑(K ⊓ K') : submodule R L) = (K : submodule R L) ⊓ (K' : submodule R L) := rfl

@[simp] lemma mem_inf (x : L) : x ∈ K ⊓ K' ↔ x ∈ K ∧ x ∈ K' :=
by rw [← mem_coe_submodule, ← mem_coe_submodule, ← mem_coe_submodule, inf_coe_to_submodule,
  submodule.mem_inf]

lemma eq_bot_iff : K = ⊥ ↔ ∀ (x : L), x ∈ K → x = 0 :=
by { rw eq_bot_iff, exact iff.rfl, }

instance subsingleton_of_bot : subsingleton (lie_subalgebra R ↥(⊥ : lie_subalgebra R L)) :=
begin
  apply subsingleton_of_bot_eq_top,
  ext ⟨x, hx⟩, change x ∈ ⊥ at hx, rw lie_subalgebra.mem_bot at hx, subst hx,
  simp only [true_iff, eq_self_iff_true, submodule.mk_eq_zero, mem_bot],
end

lemma subsingleton_bot : subsingleton ↥(⊥ : lie_subalgebra R L) :=
show subsingleton ((⊥ : lie_subalgebra R L) : set L), by simp

variables (R L)

lemma well_founded_of_noetherian [is_noetherian R L] :
  well_founded ((>) : lie_subalgebra R L → lie_subalgebra R L → Prop) :=
  let f : ((>) : lie_subalgebra R L → lie_subalgebra R L → Prop) →r
          ((>) : submodule R L → submodule R L → Prop) :=
  { to_fun       := coe,
    map_rel' := λ N N' h, h, }
in rel_hom_class.well_founded f (is_noetherian_iff_well_founded.mp infer_instance)

variables {R L K K' f}

section nested_subalgebras

variables (h : K ≤ K')

/-- Given two nested Lie subalgebras `K ⊆ K'`, the inclusion `K ↪ K'` is a morphism of Lie
algebras. -/
def hom_of_le : K →ₗ⁅R⁆ K' :=
{ map_lie' := λ x y, rfl,
  ..submodule.of_le h }

@[simp] lemma coe_hom_of_le (x : K) : (hom_of_le h x : L) = x := rfl

lemma hom_of_le_apply (x : K) : hom_of_le h x = ⟨x.1, h x.2⟩ := rfl

lemma hom_of_le_injective : function.injective (hom_of_le h) :=
λ x y, by simp only [hom_of_le_apply, imp_self, subtype.mk_eq_mk, set_like.coe_eq_coe,
  subtype.val_eq_coe]

/-- Given two nested Lie subalgebras `K ⊆ K'`, we can view `K` as a Lie subalgebra of `K'`,
regarded as Lie algebra in its own right. -/
def of_le : lie_subalgebra R K' := (hom_of_le h).range

@[simp] lemma mem_of_le (x : K') : x ∈ of_le h ↔ (x : L) ∈ K :=
begin
  simp only [of_le, hom_of_le_apply, lie_hom.mem_range],
  split,
  { rintros ⟨y, rfl⟩, exact y.property, },
  { intros h, use ⟨(x : L), h⟩, simp, },
end

lemma of_le_eq_comap_incl : of_le h = K.comap K'.incl :=
by { ext, rw mem_of_le, refl, }

@[simp] lemma coe_of_le : (of_le h : submodule R K') = (submodule.of_le h).range := rfl

/-- Given nested Lie subalgebras `K ⊆ K'`, there is a natural equivalence from `K` to its image in
`K'`.  -/
noncomputable def equiv_of_le : K ≃ₗ⁅R⁆ of_le h :=
(hom_of_le h).equiv_range_of_injective (hom_of_le_injective h)

@[simp]

end nested_subalgebras

lemma map_le_iff_le_comap {K : lie_subalgebra R L} {K' : lie_subalgebra R L₂} :
  map f K ≤ K' ↔ K ≤ comap f K' := set.image_subset_iff

lemma gc_map_comap : galois_connection (map f) (comap f) := λ K K', map_le_iff_le_comap

end lattice_structure

section lie_span

variables (R L) (s : set L)

/-- The Lie subalgebra of a Lie algebra `L` generated by a subset `s ⊆ L`. -/
def lie_span : lie_subalgebra R L := Inf {N | s ⊆ N}

variables {R L s}

lemma mem_lie_span {x : L} : x ∈ lie_span R L s ↔ ∀ K : lie_subalgebra R L, s ⊆ K → x ∈ K :=
by { change x ∈ (lie_span R L s : set L) ↔ _, erw Inf_coe, exact set.mem_Inter₂, }

lemma subset_lie_span : s ⊆ lie_span R L s :=
by { intros m hm, erw mem_lie_span, intros K hK, exact hK hm, }

lemma submodule_span_le_lie_span : submodule.span R s ≤ lie_span R L s :=
by { rw submodule.span_le, apply subset_lie_span, }

lemma lie_span_le {K} : lie_span R L s ≤ K ↔ s ⊆ K :=
begin
  split,
  { exact set.subset.trans subset_lie_span, },
  { intros hs m hm, rw mem_lie_span at hm, exact hm _ hs, },
end

lemma lie_span_mono {t : set L} (h : s ⊆ t) : lie_span R L s ≤ lie_span R L t :=
by { rw lie_span_le, exact set.subset.trans h subset_lie_span, }

lemma lie_span_eq : lie_span R L (K : set L) = K :=
le_antisymm (lie_span_le.mpr rfl.subset) subset_lie_span

lemma coe_lie_span_submodule_eq_iff {p : submodule R L} :
  (lie_span R L (p : set L) : submodule R L) = p ↔ ∃ (K : lie_subalgebra R L), ↑K = p :=
begin
  rw p.exists_lie_subalgebra_coe_eq_iff, split; intros h,
  { intros x m hm, rw [← h, mem_coe_submodule], exact lie_mem _ (subset_lie_span hm), },
  { rw [← coe_to_submodule_mk p h, coe_to_submodule, coe_to_submodule_eq_iff, lie_span_eq], },
end

variables (R L)

/-- `lie_span` forms a Galois insertion with the coercion from `lie_subalgebra` to `set`. -/
protected def gi : galois_insertion (lie_span R L : set L → lie_subalgebra R L) coe :=
{ choice    := λ s _, lie_span R L s,
  gc        := λ s t, lie_span_le,
  le_l_u    := λ s, subset_lie_span,
  choice_eq := λ s h, rfl }

@[simp] lemma span_empty : lie_span R L (∅ : set L) = ⊥ :=
(lie_subalgebra.gi R L).gc.l_bot

@[simp] lemma span_univ : lie_span R L (set.univ : set L) = ⊤ :=
eq_top_iff.2 $ set_like.le_def.2 $ subset_lie_span

variables {L}

lemma span_union (s t : set L) : lie_span R L (s ∪ t) = lie_span R L s ⊔ lie_span R L t :=
(lie_subalgebra.gi R L).gc.l_sup

lemma span_Union {ι} (s : ι → set L) : lie_span R L (⋃ i, s i) = ⨆ i, lie_span R L (s i) :=
(lie_subalgebra.gi R L).gc.l_supr

end lie_span

end lie_subalgebra

end lie_subalgebra

namespace lie_equiv

variables {R : Type u} {L₁ : Type v} {L₂ : Type w}
variables [comm_ring R] [lie_ring L₁] [lie_ring L₂] [lie_algebra R L₁] [lie_algebra R L₂]

/-- An injective Lie algebra morphism is an equivalence onto its range. -/
noncomputable def of_injective (f : L₁ →ₗ⁅R⁆ L₂) (h : function.injective f) :
  L₁ ≃ₗ⁅R⁆ f.range :=
{ map_lie' := λ x y, by { apply set_coe.ext, simpa },
  .. linear_equiv.of_injective (f : L₁ →ₗ[R] L₂) $ by rwa [lie_hom.coe_to_linear_map] }

@[simp] lemma of_injective_apply (f : L₁ →ₗ⁅R⁆ L₂) (h : function.injective f) (x : L₁) :
  ↑(of_injective f h x) = f x := rfl

variables (L₁' L₁'' : lie_subalgebra R L₁) (L₂' : lie_subalgebra R L₂)

/-- Lie subalgebras that are equal as sets are equivalent as Lie algebras. -/
def of_eq (h : (L₁' : set L₁) = L₁'') : L₁' ≃ₗ⁅R⁆ L₁'' :=
{ map_lie' := λ x y, by { apply set_coe.ext, simp, },
  ..(linear_equiv.of_eq ↑L₁' ↑L₁''
      (by {ext x, change x ∈ (L₁' : set L₁) ↔ x ∈ (L₁'' : set L₁), rw h, } )) }

@[simp] lemma of_eq_apply (L L' : lie_subalgebra R L₁) (h : (L : set L₁) = L') (x : L) :
  (↑(of_eq L L' h x) : L₁) = x := rfl

variables (e : L₁ ≃ₗ⁅R⁆ L₂)

/-- An equivalence of Lie algebras restricts to an equivalence from any Lie subalgebra onto its
image. -/
def lie_subalgebra_map : L₁'' ≃ₗ⁅R⁆ (L₁''.map e : lie_subalgebra R L₂) :=
{ map_lie' := λ x y, by { apply set_coe.ext, exact lie_hom.map_lie (↑e : L₁ →ₗ⁅R⁆ L₂) ↑x ↑y, }
  ..(linear_equiv.submodule_map (e : L₁ ≃ₗ[R] L₂) ↑L₁'') }

@[simp] lemma lie_subalgebra_map_apply (x : L₁'') : ↑(e.lie_subalgebra_map _  x) = e x := rfl

/-- An equivalence of Lie algebras restricts to an equivalence from any Lie subalgebra onto its
image. -/
def of_subalgebras (h : L₁'.map ↑e = L₂') : L₁' ≃ₗ⁅R⁆ L₂' :=
{ map_lie' := λ x y, by { apply set_coe.ext, exact lie_hom.map_lie (↑e : L₁ →ₗ⁅R⁆ L₂) ↑x ↑y, },
  ..(linear_equiv.of_submodules (e : L₁ ≃ₗ[R] L₂) ↑L₁' ↑L₂' (by { rw ←h, refl, })) }

@[simp] lemma of_subalgebras_apply (h : L₁'.map ↑e = L₂') (x : L₁') :
  ↑(e.of_subalgebras _ _ h x) = e x := rfl

@[simp] lemma of_subalgebras_symm_apply (h : L₁'.map ↑e = L₂') (x : L₂') :
  ↑((e.of_subalgebras _ _ h).symm x) = e.symm x := rfl

end lie_equiv


/-
Copyright (c) 2022 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov, Heather Macbeth

! This file was ported from Lean 3 source module analysis.normed.group.ball_sphere
! leanprover-community/mathlib commit 69c6a5a12d8a2b159f20933e60115a4f2de62b58
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Analysis.Normed.Group.Basic

/-!
# Negation on spheres and balls

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

In this file we define `has_involutive_neg` instances for spheres, open balls, and closed balls in a
semi normed group.
-/

open Metric Set

variable {E : Type _} [SeminormedAddCommGroup E] {r : ℝ}

/-- We equip the sphere, in a seminormed group, with a formal operation of negation, namely the
antipodal map. -/
instance : InvolutiveNeg (sphere (0 : E) r)
    where
  neg := Subtype.map Neg.neg fun w => by simp
  neg_neg x := Subtype.ext <| neg_neg x

/- warning: coe_neg_sphere -> coe_neg_sphere is a dubious translation:
lean 3 declaration is
  forall {E : Type.{u1}} [_inst_1 : SeminormedAddCommGroup.{u1} E] {r : Real} (v : coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)), Eq.{succ u1} E ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeSubtype.{succ u1} E (fun (x : E) => Membership.Mem.{u1, u1} E (Set.{u1} E) (Set.hasMem.{u1} E) x (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)))))) (Neg.neg.{u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) (InvolutiveNeg.toHasNeg.{u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) (Metric.sphere.hasInvolutiveNeg.{u1} E _inst_1 r)) v)) (Neg.neg.{u1} E (SubNegMonoid.toHasNeg.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1)))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeSubtype.{succ u1} E (fun (x : E) => Membership.Mem.{u1, u1} E (Set.{u1} E) (Set.hasMem.{u1} E) x (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)))))) v))
but is expected to have type
  forall {E : Type.{u1}} [_inst_1 : SeminormedAddCommGroup.{u1} E] {r : Real} (v : Set.Elem.{u1} E (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)), Eq.{succ u1} E (Subtype.val.{succ u1} E (fun (x : E) => Membership.mem.{u1, u1} E (Set.{u1} E) (Set.instMembershipSet.{u1} E) x (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (Neg.neg.{u1} (Set.Elem.{u1} E (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (InvolutiveNeg.toNeg.{u1} (Set.Elem.{u1} E (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (instInvolutiveNegElemSphereToPseudoMetricSpaceOfNatToOfNat0ToZeroToNegZeroClassToSubNegZeroMonoidToSubtractionMonoidToDivisionAddCommMonoidToAddCommGroup.{u1} E _inst_1 r)) v)) (Neg.neg.{u1} E (NegZeroClass.toNeg.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))) (Subtype.val.{succ u1} E (fun (x : E) => Membership.mem.{u1, u1} E (Set.{u1} E) (Set.instMembershipSet.{u1} E) x (Metric.sphere.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) v))
Case conversion may be inaccurate. Consider using '#align coe_neg_sphere coe_neg_sphereₓ'. -/
@[simp]
theorem coe_neg_sphere {r : ℝ} (v : sphere (0 : E) r) : ↑(-v) = (-v : E) :=
  rfl
#align coe_neg_sphere coe_neg_sphere

instance : ContinuousNeg (sphere (0 : E) r) :=
  ⟨continuous_neg.subtypeMap _⟩

/-- We equip the ball, in a seminormed group, with a formal operation of negation, namely the
antipodal map. -/
instance {r : ℝ} : InvolutiveNeg (ball (0 : E) r)
    where
  neg := Subtype.map Neg.neg fun w => by simp
  neg_neg x := Subtype.ext <| neg_neg x

/- warning: coe_neg_ball -> coe_neg_ball is a dubious translation:
lean 3 declaration is
  forall {E : Type.{u1}} [_inst_1 : SeminormedAddCommGroup.{u1} E] {r : Real} (v : coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)), Eq.{succ u1} E ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeSubtype.{succ u1} E (fun (x : E) => Membership.Mem.{u1, u1} E (Set.{u1} E) (Set.hasMem.{u1} E) x (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)))))) (Neg.neg.{u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) (InvolutiveNeg.toHasNeg.{u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) (Metric.ball.hasInvolutiveNeg.{u1} E _inst_1 r)) v)) (Neg.neg.{u1} E (SubNegMonoid.toHasNeg.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1)))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeSubtype.{succ u1} E (fun (x : E) => Membership.Mem.{u1, u1} E (Set.{u1} E) (Set.hasMem.{u1} E) x (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)))))) v))
but is expected to have type
  forall {E : Type.{u1}} [_inst_1 : SeminormedAddCommGroup.{u1} E] {r : Real} (v : Set.Elem.{u1} E (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)), Eq.{succ u1} E (Subtype.val.{succ u1} E (fun (x : E) => Membership.mem.{u1, u1} E (Set.{u1} E) (Set.instMembershipSet.{u1} E) x (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (Neg.neg.{u1} (Set.Elem.{u1} E (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (InvolutiveNeg.toNeg.{u1} (Set.Elem.{u1} E (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (instInvolutiveNegElemBallToPseudoMetricSpaceOfNatToOfNat0ToZeroToNegZeroClassToSubNegZeroMonoidToSubtractionMonoidToDivisionAddCommMonoidToAddCommGroup.{u1} E _inst_1 r)) v)) (Neg.neg.{u1} E (NegZeroClass.toNeg.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))) (Subtype.val.{succ u1} E (fun (x : E) => Membership.mem.{u1, u1} E (Set.{u1} E) (Set.instMembershipSet.{u1} E) x (Metric.ball.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) v))
Case conversion may be inaccurate. Consider using '#align coe_neg_ball coe_neg_ballₓ'. -/
@[simp]
theorem coe_neg_ball {r : ℝ} (v : ball (0 : E) r) : ↑(-v) = (-v : E) :=
  rfl
#align coe_neg_ball coe_neg_ball

instance : ContinuousNeg (ball (0 : E) r) :=
  ⟨continuous_neg.subtypeMap _⟩

/-- We equip the closed ball, in a seminormed group, with a formal operation of negation, namely the
antipodal map. -/
instance {r : ℝ} : InvolutiveNeg (closedBall (0 : E) r)
    where
  neg := Subtype.map Neg.neg fun w => by simp
  neg_neg x := Subtype.ext <| neg_neg x

/- warning: coe_neg_closed_ball -> coe_neg_closedBall is a dubious translation:
lean 3 declaration is
  forall {E : Type.{u1}} [_inst_1 : SeminormedAddCommGroup.{u1} E] {r : Real} (v : coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)), Eq.{succ u1} E ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeSubtype.{succ u1} E (fun (x : E) => Membership.Mem.{u1, u1} E (Set.{u1} E) (Set.hasMem.{u1} E) x (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)))))) (Neg.neg.{u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) (InvolutiveNeg.toHasNeg.{u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) (Metric.closedBall.hasInvolutiveNeg.{u1} E _inst_1 r)) v)) (Neg.neg.{u1} E (SubNegMonoid.toHasNeg.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1)))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} E) Type.{u1} (Set.hasCoeToSort.{u1} E) (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)) E (coeSubtype.{succ u1} E (fun (x : E) => Membership.Mem.{u1, u1} E (Set.{u1} E) (Set.hasMem.{u1} E) x (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (OfNat.mk.{u1} E 0 (Zero.zero.{u1} E (AddZeroClass.toHasZero.{u1} E (AddMonoid.toAddZeroClass.{u1} E (SubNegMonoid.toAddMonoid.{u1} E (AddGroup.toSubNegMonoid.{u1} E (SeminormedAddGroup.toAddGroup.{u1} E (SeminormedAddCommGroup.toSeminormedAddGroup.{u1} E _inst_1))))))))) r)))))) v))
but is expected to have type
  forall {E : Type.{u1}} [_inst_1 : SeminormedAddCommGroup.{u1} E] {r : Real} (v : Set.Elem.{u1} E (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)), Eq.{succ u1} E (Subtype.val.{succ u1} E (fun (x : E) => Membership.mem.{u1, u1} E (Set.{u1} E) (Set.instMembershipSet.{u1} E) x (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (Neg.neg.{u1} (Set.Elem.{u1} E (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (InvolutiveNeg.toNeg.{u1} (Set.Elem.{u1} E (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) (instInvolutiveNegElemClosedBallToPseudoMetricSpaceOfNatToOfNat0ToZeroToNegZeroClassToSubNegZeroMonoidToSubtractionMonoidToDivisionAddCommMonoidToAddCommGroup.{u1} E _inst_1 r)) v)) (Neg.neg.{u1} E (NegZeroClass.toNeg.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))) (Subtype.val.{succ u1} E (fun (x : E) => Membership.mem.{u1, u1} E (Set.{u1} E) (Set.instMembershipSet.{u1} E) x (Metric.closedBall.{u1} E (SeminormedAddCommGroup.toPseudoMetricSpace.{u1} E _inst_1) (OfNat.ofNat.{u1} E 0 (Zero.toOfNat0.{u1} E (NegZeroClass.toZero.{u1} E (SubNegZeroMonoid.toNegZeroClass.{u1} E (SubtractionMonoid.toSubNegZeroMonoid.{u1} E (SubtractionCommMonoid.toSubtractionMonoid.{u1} E (AddCommGroup.toDivisionAddCommMonoid.{u1} E (SeminormedAddCommGroup.toAddCommGroup.{u1} E _inst_1)))))))) r)) v))
Case conversion may be inaccurate. Consider using '#align coe_neg_closed_ball coe_neg_closedBallₓ'. -/
@[simp]
theorem coe_neg_closedBall {r : ℝ} (v : closedBall (0 : E) r) : ↑(-v) = (-v : E) :=
  rfl
#align coe_neg_closed_ball coe_neg_closedBall

instance : ContinuousNeg (closedBall (0 : E) r) :=
  ⟨continuous_neg.subtypeMap _⟩


/-
Copyright (c) 2021 OpenAI. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kunhao Zheng, Stanislas Polu, David Renshaw, OpenAI GPT-f
-/
import mathzoo.imports.miniF2F

open_locale nat rat real big_operators topological_space

theorem mathd_numbertheory_342 :
  54 % 6 = 0 :=
begin
  norm_num,
end


/-
Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro

Computational realization of filters (experimental).
-/
import order.filter.cofinite
open set filter

/-- A `cfilter α σ` is a realization of a filter (base) on `α`,
  represented by a type `σ` together with operations for the top element and
  the binary inf operation. -/
structure cfilter (α σ : Type*) [partial_order α] :=
(f : σ → α)
(pt : σ)
(inf : σ → σ → σ)
(inf_le_left : ∀ a b : σ, f (inf a b) ≤ f a)
(inf_le_right : ∀ a b : σ, f (inf a b) ≤ f b)

variables {α : Type*} {β : Type*} {σ : Type*} {τ : Type*}

namespace cfilter
section
variables [partial_order α] (F : cfilter α σ)

instance : has_coe_to_fun (cfilter α σ) := ⟨_, cfilter.f⟩

@[simp] theorem coe_mk (f pt inf h₁ h₂ a) : (@cfilter.mk α σ _ f pt inf h₁ h₂) a = f a := rfl

/-- Map a cfilter to an equivalent representation type. -/
def of_equiv (E : σ ≃ τ) : cfilter α σ → cfilter α τ
| ⟨f, p, g, h₁, h₂⟩ :=
  { f            := λ a, f (E.symm a),
    pt           := E p,
    inf          := λ a b, E (g (E.symm a) (E.symm b)),
    inf_le_left  := λ a b, by simpa using h₁ (E.symm a) (E.symm b),
    inf_le_right := λ a b, by simpa using h₂ (E.symm a) (E.symm b) }

@[simp] theorem of_equiv_val (E : σ ≃ τ) (F : cfilter α σ) (a : τ) :
  F.of_equiv E a = F (E.symm a) := by cases F; refl

end

/-- The filter represented by a `cfilter` is the collection of supersets of
  elements of the filter base. -/
def to_filter (F : cfilter (set α) σ) : filter α :=
{ sets             := {a | ∃ b, F b ⊆ a},
  univ_sets        := ⟨F.pt, subset_univ _⟩,
  sets_of_superset := λ x y ⟨b, h⟩ s, ⟨b, subset.trans h s⟩,
  inter_sets       := λ x y ⟨a, h₁⟩ ⟨b, h₂⟩, ⟨F.inf a b,
    subset_inter (subset.trans (F.inf_le_left _ _) h₁) (subset.trans (F.inf_le_right _ _) h₂)⟩ }

@[simp] theorem mem_to_filter_sets (F : cfilter (set α) σ) {a : set α} :
  a ∈ F.to_filter ↔ ∃ b, F b ⊆ a := iff.rfl

end cfilter

/-- A realizer for filter `f` is a cfilter which generates `f`. -/
structure filter.realizer (f : filter α) :=
(σ : Type*)
(F : cfilter (set α) σ)
(eq : F.to_filter = f)

protected def cfilter.to_realizer (F : cfilter (set α) σ) : F.to_filter.realizer := ⟨σ, F, rfl⟩

namespace filter.realizer

theorem mem_sets {f : filter α} (F : f.realizer) {a : set α} : a ∈ f ↔ ∃ b, F.F b ⊆ a :=
by cases F; subst f; simp

-- Used because it has better definitional equalities than the eq.rec proof
def of_eq {f g : filter α} (e : f = g) (F : f.realizer) : g.realizer :=
⟨F.σ, F.F, F.eq.trans e⟩

/-- A filter realizes itself. -/
def of_filter (f : filter α) : f.realizer := ⟨f.sets,
{ f            := subtype.val,
  pt           := ⟨univ, univ_mem_sets⟩,
  inf          := λ ⟨x, h₁⟩ ⟨y, h₂⟩, ⟨_, inter_mem_sets h₁ h₂⟩,
  inf_le_left  := λ ⟨x, h₁⟩ ⟨y, h₂⟩, inter_subset_left x y,
  inf_le_right := λ ⟨x, h₁⟩ ⟨y, h₂⟩, inter_subset_right x y },
filter_eq $ set.ext $ λ x, set_coe.exists.trans exists_sets_subset_iff⟩

/-- Transfer a filter realizer to another realizer on a different base type. -/
def of_equiv {f : filter α} (F : f.realizer) (E : F.σ ≃ τ) : f.realizer :=
⟨τ, F.F.of_equiv E, by refine eq.trans _ F.eq; exact filter_eq (set.ext $ λ x,
⟨λ ⟨s, h⟩, ⟨E.symm s, by simpa using h⟩, λ ⟨t, h⟩, ⟨E t, by simp [h]⟩⟩)⟩

@[simp] theorem of_equiv_σ {f : filter α} (F : f.realizer) (E : F.σ ≃ τ) :
  (F.of_equiv E).σ = τ := rfl
@[simp]

/-- `unit` is a realizer for the principal filter -/
protected def principal (s : set α) : (principal s).realizer := ⟨unit,
{ f            := λ _, s,
  pt           := (),
  inf          := λ _ _, (),
  inf_le_left  := λ _ _, le_refl _,
  inf_le_right := λ _ _, le_refl _ },
filter_eq $ set.ext $ λ x,
⟨λ ⟨_, s⟩, s, λ h, ⟨(), h⟩⟩⟩

@[simp] theorem principal_σ (s : set α) : (realizer.principal s).σ = unit := rfl
@[simp] theorem principal_F (s : set α) (u : unit) : (realizer.principal s).F u = s := rfl

/-- `unit` is a realizer for the top filter -/
protected def top : (⊤ : filter α).realizer :=
(realizer.principal _).of_eq principal_univ

@[simp] theorem top_σ : (@realizer.top α).σ = unit := rfl
@[simp] theorem top_F (u : unit) : (@realizer.top α).F u = univ := rfl

/-- `unit` is a realizer for the bottom filter -/
protected def bot : (⊥ : filter α).realizer :=
(realizer.principal _).of_eq principal_empty

@[simp] theorem bot_σ : (@realizer.bot α).σ = unit := rfl
@[simp] theorem bot_F (u : unit) : (@realizer.bot α).F u = ∅ := rfl

/-- Construct a realizer for `map m f` given a realizer for `f` -/
protected def map (m : α → β) {f : filter α} (F : f.realizer) : (map m f).realizer := ⟨F.σ,
{ f            := λ s, image m (F.F s),
  pt           := F.F.pt,
  inf          := F.F.inf,
  inf_le_left  := λ a b, image_subset _ (F.F.inf_le_left _ _),
  inf_le_right := λ a b, image_subset _ (F.F.inf_le_right _ _) },
filter_eq $ set.ext $ λ x, by simp [cfilter.to_filter]; rw F.mem_sets; refl ⟩

@[simp] theorem map_σ (m : α → β) {f : filter α} (F : f.realizer) : (F.map m).σ = F.σ := rfl
@[simp] theorem map_F (m : α → β) {f : filter α} (F : f.realizer) (s) :
  (F.map m).F s = image m (F.F s) := rfl

/-- Construct a realizer for `comap m f` given a realizer for `f` -/
protected def comap (m : α → β) {f : filter β} (F : f.realizer) : (comap m f).realizer := ⟨F.σ,
{ f            := λ s, preimage m (F.F s),
  pt           := F.F.pt,
  inf          := F.F.inf,
  inf_le_left  := λ a b, preimage_mono (F.F.inf_le_left _ _),
  inf_le_right := λ a b, preimage_mono (F.F.inf_le_right _ _) },
filter_eq $ set.ext $ λ x, by cases F; subst f; simp [cfilter.to_filter, mem_comap_sets]; exact
⟨λ ⟨s, h⟩, ⟨_, ⟨s, subset.refl _⟩, h⟩,
 λ ⟨y, ⟨s, h⟩, h₂⟩, ⟨s, subset.trans (preimage_mono h) h₂⟩⟩⟩

/-- Construct a realizer for the sup of two filters -/
protected def sup {f g : filter α} (F : f.realizer) (G : g.realizer) :
  (f ⊔ g).realizer := ⟨F.σ × G.σ,
{ f            := λ ⟨s, t⟩, F.F s ∪ G.F t,
  pt           := (F.F.pt, G.F.pt),
  inf          := λ ⟨a, a'⟩ ⟨b, b'⟩, (F.F.inf a b, G.F.inf a' b'),
  inf_le_left  := λ ⟨a, a'⟩ ⟨b, b'⟩, union_subset_union (F.F.inf_le_left _ _) (G.F.inf_le_left _ _),
  inf_le_right := λ ⟨a, a'⟩ ⟨b, b'⟩, union_subset_union (F.F.inf_le_right _ _)
                    (G.F.inf_le_right _ _) },
filter_eq $ set.ext $ λ x, by cases F; cases G; substs f g; simp [cfilter.to_filter]; exact
⟨λ ⟨s, t, h⟩, ⟨⟨s, subset.trans (subset_union_left _ _) h⟩,
               ⟨t, subset.trans (subset_union_right _ _) h⟩⟩,
 λ ⟨⟨s, h₁⟩, ⟨t, h₂⟩⟩, ⟨s, t, union_subset h₁ h₂⟩⟩⟩

/-- Construct a realizer for the inf of two filters -/
protected def inf {f g : filter α} (F : f.realizer) (G : g.realizer) :
  (f ⊓ g).realizer := ⟨F.σ × G.σ,
{ f            := λ ⟨s, t⟩, F.F s ∩ G.F t,
  pt           := (F.F.pt, G.F.pt),
  inf          := λ ⟨a, a'⟩ ⟨b, b'⟩, (F.F.inf a b, G.F.inf a' b'),
  inf_le_left  := λ ⟨a, a'⟩ ⟨b, b'⟩, inter_subset_inter (F.F.inf_le_left _ _) (G.F.inf_le_left _ _),
  inf_le_right := λ ⟨a, a'⟩ ⟨b, b'⟩, inter_subset_inter (F.F.inf_le_right _ _)
                    (G.F.inf_le_right _ _) },
filter_eq $ set.ext $ λ x, by cases F; cases G; substs f g; simp [cfilter.to_filter]; exact
⟨λ ⟨s, t, h⟩, ⟨_, ⟨s, subset.refl _⟩, _, ⟨t, subset.refl _⟩, h⟩,
 λ ⟨y, ⟨s, h₁⟩, z, ⟨t, h₂⟩, h⟩, ⟨s, t, subset.trans (inter_subset_inter h₁ h₂) h⟩⟩⟩

/-- Construct a realizer for the cofinite filter -/
protected def cofinite [decidable_eq α] : (@cofinite α).realizer := ⟨finset α,
{ f            := λ s, {a | a ∉ s},
  pt           := ∅,
  inf          := (∪),
  inf_le_left  := λ s t a, mt (finset.mem_union_left _),
  inf_le_right := λ s t a, mt (finset.mem_union_right _) },
filter_eq $ set.ext $ λ x,
⟨λ ⟨s, h⟩, s.finite_to_set.subset (compl_subset_comm.1 h),
 λ ⟨fs⟩, by exactI ⟨xᶜ.to_finset, λ a (h : a ∉ xᶜ.to_finset),
  classical.by_contradiction $ λ h', h (mem_to_finset.2 h')⟩⟩⟩

/-- Construct a realizer for filter bind -/
protected def bind {f : filter α} {m : α → filter β} (F : f.realizer) (G : ∀ i, (m i).realizer) :
  (f.bind m).realizer :=
⟨Σ s : F.σ, Π i ∈ F.F s, (G i).σ,
{ f            := λ ⟨s, f⟩, ⋃ i ∈ F.F s, (G i).F (f i H),
  pt           := ⟨F.F.pt, λ i H, (G i).F.pt⟩,
  inf          := λ ⟨a, f⟩ ⟨b, f'⟩, ⟨F.F.inf a b, λ i h,
    (G i).F.inf (f i (F.F.inf_le_left _ _ h)) (f' i (F.F.inf_le_right _ _ h))⟩,
  inf_le_left  := λ ⟨a, f⟩ ⟨b, f'⟩ x,
    show (x ∈ ⋃ (i : α) (H : i ∈ F.F (F.F.inf a b)), _) →
          x ∈ ⋃ i (H : i ∈ F.F a), ((G i).F) (f i H), by simp; exact
    λ i h₁ h₂, ⟨i, F.F.inf_le_left _ _ h₁, (G i).F.inf_le_left _ _ h₂⟩,
  inf_le_right := λ ⟨a, f⟩ ⟨b, f'⟩ x,
    show (x ∈ ⋃ (i : α) (H : i ∈ F.F (F.F.inf a b)), _) →
          x ∈ ⋃ i (H : i ∈ F.F b), ((G i).F) (f' i H), by simp; exact
    λ i h₁ h₂, ⟨i, F.F.inf_le_right _ _ h₁, (G i).F.inf_le_right _ _ h₂⟩ },
filter_eq $ set.ext $ λ x,
by cases F with _ F _; subst f; simp [cfilter.to_filter, mem_bind_sets]; exact
⟨λ ⟨s, f, h⟩, ⟨F s, ⟨s, subset.refl _⟩, λ i H, (G i).mem_sets.2
   ⟨f i H, λ a h', h ⟨_, ⟨i, rfl⟩, _, ⟨H, rfl⟩, h'⟩⟩⟩,
 λ ⟨y, ⟨s, h⟩, f⟩,
  let ⟨f', h'⟩ := classical.axiom_of_choice (λ i:F s, (G i).mem_sets.1 (f i (h i.2))) in
  ⟨s, λ i h, f' ⟨i, h⟩, λ a ⟨_, ⟨i, rfl⟩, _, ⟨H, rfl⟩, m⟩, h' ⟨_, H⟩ m⟩⟩⟩

/-- Construct a realizer for indexed supremum -/
protected def Sup {f : α → filter β} (F : ∀ i, (f i).realizer) : (⨆ i, f i).realizer :=
let F' : (⨆ i, f i).realizer :=
  ((realizer.bind realizer.top F).of_eq $
    filter_eq $ set.ext $ by simp [filter.bind, eq_univ_iff_forall, supr_sets_eq]) in
F'.of_equiv $ show (Σ u:unit, Π (i : α), true → (F i).σ) ≃ Π i, (F i).σ, from
⟨λ⟨_,f⟩ i, f i ⟨⟩, λ f, ⟨(), λ i _, f i⟩,
 λ ⟨⟨⟩, f⟩, by dsimp; congr; simp, λ f, rfl⟩

/-- Construct a realizer for the product of filters -/
protected def prod {f g : filter α} (F : f.realizer) (G : g.realizer) : (f.prod g).realizer :=
(F.comap _).inf (G.comap _)

theorem le_iff {f g : filter α} (F : f.realizer) (G : g.realizer) :
  f ≤ g ↔ ∀ b : G.σ, ∃ a : F.σ, F.F a ≤ G.F b :=
⟨λ H t, F.mem_sets.1 (H (G.mem_sets.2 ⟨t, subset.refl _⟩)),
 λ H x h, F.mem_sets.2 $
   let ⟨s, h₁⟩ := G.mem_sets.1 h, ⟨t, h₂⟩ := H s in ⟨t, subset.trans h₂ h₁⟩⟩

theorem tendsto_iff (f : α → β) {l₁ : filter α} {l₂ : filter β} (L₁ : l₁.realizer)
  (L₂ : l₂.realizer) :
  tendsto f l₁ l₂ ↔ ∀ b, ∃ a, ∀ x ∈ L₁.F a, f x ∈ L₂.F b :=
(le_iff (L₁.map f) L₂).trans $ forall_congr $ λ b, exists_congr $ λ a, image_subset_iff

theorem ne_bot_iff {f : filter α} (F : f.realizer) :
  f ≠ ⊥ ↔ ∀ a : F.σ, (F.F a).nonempty :=
begin
  classical,
  rw [not_iff_comm, ← le_bot_iff, F.le_iff realizer.bot, not_forall],
  simp only [set.not_nonempty_iff_eq_empty],
  exact ⟨λ ⟨x, e⟩ _, ⟨x, le_of_eq e⟩,
    λ h, let ⟨x, h⟩ := h () in ⟨x, le_bot_iff.1 h⟩⟩
end

end filter.realizer


theorem t1 : True := _
theorem t2 : True := t1

def f (x : Nat) : Nat := x + _

#check f

def g (x : Nat) : Nat :=
  f (x + x)

#eval g 0


/-
Copyright (c) 2019 Jesse Michael Han. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author(s): Jesse Michael Han

Tests for `finish using [...]`
-/

import tactic.finish
import algebra.ordered_ring

section list_rev
open list
variable {α : Type*}

def append1 (a : α) : list α → list α
| nil      := [a]
| (b :: l) := b :: (append1 l)

def rev : list α → list α
| nil := nil
| (a :: l) := append1 a (rev l)

lemma hd_rev (a : α) (l : list α) :
  a :: rev l =  rev (append1 a l) :=
begin
  induction l with l_hd l_tl ih, refl,
  -- finish -- fails
  -- finish[rev, append1] -- fails
  -- finish[rev, append1, ih] -- fails
  -- finish[rev, append1, ih.symm] -- times out
  finish using [rev, append1]
end

end list_rev

section barber
variables (man : Type) (barber : man)
variable  (shaves : man → man → Prop)

example (h : ∀ x : man, shaves barber x ↔ ¬ shaves x x) : false :=
by finish using [h barber]

end barber

constant real : Type
@[instance] constant orreal : ordered_ring real

-- TODO(Mario): suspicious fix
@[irreducible] noncomputable instance : has_lt real := by apply_instance
constants (log exp : real → real)
constant  log_exp_eq : ∀ x, log (exp x) = x
constant  exp_log_eq : ∀ {x}, x > 0 → exp (log x) = x
constant  exp_pos    : ∀ x, exp x > 0
constant  exp_add    : ∀ x y, exp (x + y) = exp x * exp y

theorem log_mul' {x y : real} (hx : x > 0) (hy : y > 0) :
  log (x * y) = log x + log y :=
by finish using [log_exp_eq, exp_log_eq, exp_add]


theorem free_fun (r : ∀ (X : Type), X → X) :
∀ (A B : Type), ∀ f : A → B, ∀ a : A, r B (f a) = f (r A a) :=
begin
intros A B f a,
let b := r (Π (a : A), B) f a,
end


import tactic

-- 1ª definición
def splitAt1 {a : Type} : ℕ → (list a) → (list a × list a)
 | 0       xs        := ([], xs)
 | _       []        := ([], [])
 | (n + 1) (x :: xs) := let (ys, zs) := splitAt1 n xs in (x :: ys, zs)

example : splitAt1 2 [1,2,3,4] = ([1,2],[3,4]) :=
begin
  simp [splitAt1],
end

-- 2ª definición
def splitAt {a : Type} : ℕ → (list a) → (list a × list a)
 | 0 xs              := ([], xs)
 | _       []        := ([], [])
 | (n + 1) (x :: xs) := (x :: (splitAt n xs).1, (splitAt n xs).2)

example : splitAt 2 [1,2,3,4] = ([1,2],[3,4]) :=
begin
  simp [splitAt],
end

example
  (a : Type)
  (n : ℕ)
  (xs : list a)
  : (λ x, (prod.fst x) ++ (prod.snd x) = xs) (splitAt n xs) :=
begin
  induction xs with d hd IH generalizing n,
  { induction n with m hm;
    simp [splitAt] },
  { induction n with m hm,
    { simp [splitAt] },
    { simp [splitAt, IH, hm] } }
end


/-
Copyright (c) 2021 Ashwin Iyengar. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kevin Buzzard, Johan Commelin, Ashwin Iyengar, Patrick Massot

! This file was ported from Lean 3 source module topology.algebra.nonarchimedean.basic
! leanprover-community/mathlib commit 932872382355f00112641d305ba0619305dc8642
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.GroupTheory.Subgroup.Basic
import Mathbin.Topology.Algebra.OpenSubgroup
import Mathbin.Topology.Algebra.Ring.Basic

/-!
# Nonarchimedean Topology

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

In this file we set up the theory of nonarchimedean topological groups and rings.

A nonarchimedean group is a topological group whose topology admits a basis of
open neighborhoods of the identity element in the group consisting of open subgroups.
A nonarchimedean ring is a topological ring whose underlying topological (additive)
group is nonarchimedean.

## Definitions

- `nonarchimedean_add_group`: nonarchimedean additive group.
- `nonarchimedean_group`: nonarchimedean multiplicative group.
- `nonarchimedean_ring`: nonarchimedean ring.

-/

open Pointwise

#print NonarchimedeanAddGroup /-
/-- An topological additive group is nonarchimedean if every neighborhood of 0
  contains an open subgroup. -/
class NonarchimedeanAddGroup (G : Type _) [AddGroup G] [TopologicalSpace G] extends
  TopologicalAddGroup G : Prop where
  is_nonarchimedean : ∀ U ∈ nhds (0 : G), ∃ V : OpenAddSubgroup G, (V : Set G) ⊆ U
#align nonarchimedean_add_group NonarchimedeanAddGroup
-/

#print NonarchimedeanGroup /-
/-- A topological group is nonarchimedean if every neighborhood of 1 contains an open subgroup. -/
@[to_additive]
class NonarchimedeanGroup (G : Type _) [Group G] [TopologicalSpace G] extends TopologicalGroup G :
  Prop where
  is_nonarchimedean : ∀ U ∈ nhds (1 : G), ∃ V : OpenSubgroup G, (V : Set G) ⊆ U
#align nonarchimedean_group NonarchimedeanGroup
#align nonarchimedean_add_group NonarchimedeanAddGroup
-/

#print NonarchimedeanRing /-
/-- An topological ring is nonarchimedean if its underlying topological additive
  group is nonarchimedean. -/
class NonarchimedeanRing (R : Type _) [Ring R] [TopologicalSpace R] extends TopologicalRing R :
  Prop where
  is_nonarchimedean : ∀ U ∈ nhds (0 : R), ∃ V : OpenAddSubgroup R, (V : Set R) ⊆ U
#align nonarchimedean_ring NonarchimedeanRing
-/

/- warning: nonarchimedean_ring.to_nonarchimedean_add_group -> NonarchimedeanRing.to_nonarchimedeanAddGroup is a dubious translation:
lean 3 declaration is
  forall (R : Type.{u1}) [_inst_1 : Ring.{u1} R] [_inst_2 : TopologicalSpace.{u1} R] [t : NonarchimedeanRing.{u1} R _inst_1 _inst_2], NonarchimedeanAddGroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2
but is expected to have type
  forall (R : Type.{u1}) [_inst_1 : Ring.{u1} R] [_inst_2 : TopologicalSpace.{u1} R] [t : NonarchimedeanRing.{u1} R _inst_1 _inst_2], NonarchimedeanAddGroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2
Case conversion may be inaccurate. Consider using '#align nonarchimedean_ring.to_nonarchimedean_add_group NonarchimedeanRing.to_nonarchimedeanAddGroupₓ'. -/
-- see Note [lower instance priority]
/-- Every nonarchimedean ring is naturally a nonarchimedean additive group. -/
instance (priority := 100) NonarchimedeanRing.to_nonarchimedeanAddGroup (R : Type _) [Ring R]
    [TopologicalSpace R] [t : NonarchimedeanRing R] : NonarchimedeanAddGroup R :=
  { t with }
#align nonarchimedean_ring.to_nonarchimedean_add_group NonarchimedeanRing.to_nonarchimedeanAddGroup

namespace NonarchimedeanGroup

variable {G : Type _} [Group G] [TopologicalSpace G] [NonarchimedeanGroup G]

variable {H : Type _} [Group H] [TopologicalSpace H] [TopologicalGroup H]

variable {K : Type _} [Group K] [TopologicalSpace K] [NonarchimedeanGroup K]

/- warning: nonarchimedean_group.nonarchimedean_of_emb -> NonarchimedeanGroup.nonarchimedean_of_emb is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] [_inst_2 : TopologicalSpace.{u1} G] [_inst_3 : NonarchimedeanGroup.{u1} G _inst_1 _inst_2] {H : Type.{u2}} [_inst_4 : Group.{u2} H] [_inst_5 : TopologicalSpace.{u2} H] [_inst_6 : TopologicalGroup.{u2} H _inst_5 _inst_4] (f : MonoidHom.{u1, u2} G H (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} H (DivInvMonoid.toMonoid.{u2} H (Group.toDivInvMonoid.{u2} H _inst_4)))), (OpenEmbedding.{u1, u2} G H _inst_2 _inst_5 (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MonoidHom.{u1, u2} G H (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} H (DivInvMonoid.toMonoid.{u2} H (Group.toDivInvMonoid.{u2} H _inst_4)))) (fun (_x : MonoidHom.{u1, u2} G H (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} H (DivInvMonoid.toMonoid.{u2} H (Group.toDivInvMonoid.{u2} H _inst_4)))) => G -> H) (MonoidHom.hasCoeToFun.{u1, u2} G H (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} H (DivInvMonoid.toMonoid.{u2} H (Group.toDivInvMonoid.{u2} H _inst_4)))) f)) -> (NonarchimedeanGroup.{u2} H _inst_4 _inst_5)
but is expected to have type
  forall {G : Type.{u2}} [_inst_1 : Group.{u2} G] [_inst_2 : TopologicalSpace.{u2} G] [_inst_3 : NonarchimedeanGroup.{u2} G _inst_1 _inst_2] {H : Type.{u1}} [_inst_4 : Group.{u1} H] [_inst_5 : TopologicalSpace.{u1} H] [_inst_6 : TopologicalGroup.{u1} H _inst_5 _inst_4] (f : MonoidHom.{u2, u1} G H (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4)))), (OpenEmbedding.{u2, u1} G H _inst_2 _inst_5 (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MonoidHom.{u2, u1} G H (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4)))) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} G H (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4)))) G H (MulOneClass.toMul.{u2} G (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1)))) (MulOneClass.toMul.{u1} H (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4)))) (MonoidHomClass.toMulHomClass.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} G H (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4)))) G H (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4))) (MonoidHom.monoidHomClass.{u2, u1} G H (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} H (DivInvMonoid.toMonoid.{u1} H (Group.toDivInvMonoid.{u1} H _inst_4)))))) f)) -> (NonarchimedeanGroup.{u1} H _inst_4 _inst_5)
Case conversion may be inaccurate. Consider using '#align nonarchimedean_group.nonarchimedean_of_emb NonarchimedeanGroup.nonarchimedean_of_embₓ'. -/
/-- If a topological group embeds into a nonarchimedean group, then it is nonarchimedean. -/
@[to_additive NonarchimedeanAddGroup.nonarchimedean_of_emb
      "If a topological group embeds into a\nnonarchimedean group, then it is nonarchimedean."]
theorem nonarchimedean_of_emb (f : G →* H) (emb : OpenEmbedding f) : NonarchimedeanGroup H :=
  {
    is_nonarchimedean := fun U hU =>
      have h₁ : f ⁻¹' U ∈ nhds (1 : G) :=
        by
        apply emb.continuous.tendsto
        rwa [f.map_one]
      let ⟨V, hV⟩ := is_nonarchimedean (f ⁻¹' U) h₁
      ⟨{ Subgroup.map f V with is_open' := emb.IsOpenMap _ V.IsOpen }, Set.image_subset_iff.2 hV⟩ }
#align nonarchimedean_group.nonarchimedean_of_emb NonarchimedeanGroup.nonarchimedean_of_emb
#align nonarchimedean_add_group.nonarchimedean_of_emb NonarchimedeanAddGroup.nonarchimedean_of_emb

/- warning: nonarchimedean_group.prod_subset -> NonarchimedeanGroup.prod_subset is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] [_inst_2 : TopologicalSpace.{u1} G] [_inst_3 : NonarchimedeanGroup.{u1} G _inst_1 _inst_2] {K : Type.{u2}} [_inst_7 : Group.{u2} K] [_inst_8 : TopologicalSpace.{u2} K] [_inst_9 : NonarchimedeanGroup.{u2} K _inst_7 _inst_8] {U : Set.{max u1 u2} (Prod.{u1, u2} G K)}, (Membership.Mem.{max u1 u2, max u1 u2} (Set.{max u1 u2} (Prod.{u1, u2} G K)) (Filter.{max u1 u2} (Prod.{u1, u2} G K)) (Filter.hasMem.{max u1 u2} (Prod.{u1, u2} G K)) U (nhds.{max u1 u2} (Prod.{u1, u2} G K) (Prod.topologicalSpace.{u1, u2} G K _inst_2 _inst_8) (OfNat.ofNat.{max u1 u2} (Prod.{u1, u2} G K) 1 (OfNat.mk.{max u1 u2} (Prod.{u1, u2} G K) 1 (One.one.{max u1 u2} (Prod.{u1, u2} G K) (Prod.hasOne.{u1, u2} G K (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) (MulOneClass.toHasOne.{u2} K (Monoid.toMulOneClass.{u2} K (DivInvMonoid.toMonoid.{u2} K (Group.toDivInvMonoid.{u2} K _inst_7)))))))))) -> (Exists.{succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (fun (V : OpenSubgroup.{u1} G _inst_1 _inst_2) => Exists.{succ u2} (OpenSubgroup.{u2} K _inst_7 _inst_8) (fun (W : OpenSubgroup.{u2} K _inst_7 _inst_8) => HasSubset.Subset.{max u1 u2} (Set.{max u1 u2} (Prod.{u1, u2} G K)) (Set.hasSubset.{max u1 u2} (Prod.{u1, u2} G K)) (Set.prod.{u1, u2} G K ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (HasLiftT.mk.{succ u1, succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (CoeTCₓ.coe.{succ u1, succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (SetLike.Set.hasCoeT.{u1, u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) G (OpenSubgroup.setLike.{u1} G _inst_1 _inst_2)))) V) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (OpenSubgroup.{u2} K _inst_7 _inst_8) (Set.{u2} K) (HasLiftT.mk.{succ u2, succ u2} (OpenSubgroup.{u2} K _inst_7 _inst_8) (Set.{u2} K) (CoeTCₓ.coe.{succ u2, succ u2} (OpenSubgroup.{u2} K _inst_7 _inst_8) (Set.{u2} K) (SetLike.Set.hasCoeT.{u2, u2} (OpenSubgroup.{u2} K _inst_7 _inst_8) K (OpenSubgroup.setLike.{u2} K _inst_7 _inst_8)))) W)) U)))
but is expected to have type
  forall {G : Type.{u2}} [_inst_1 : Group.{u2} G] [_inst_2 : TopologicalSpace.{u2} G] [_inst_3 : NonarchimedeanGroup.{u2} G _inst_1 _inst_2] {K : Type.{u1}} [_inst_7 : Group.{u1} K] [_inst_8 : TopologicalSpace.{u1} K] [_inst_9 : NonarchimedeanGroup.{u1} K _inst_7 _inst_8] {U : Set.{max u2 u1} (Prod.{u2, u1} G K)}, (Membership.mem.{max u2 u1, max u2 u1} (Set.{max u2 u1} (Prod.{u2, u1} G K)) (Filter.{max u2 u1} (Prod.{u2, u1} G K)) (instMembershipSetFilter.{max u2 u1} (Prod.{u2, u1} G K)) U (nhds.{max u2 u1} (Prod.{u2, u1} G K) (instTopologicalSpaceProd.{u2, u1} G K _inst_2 _inst_8) (OfNat.ofNat.{max u2 u1} (Prod.{u2, u1} G K) 1 (One.toOfNat1.{max u2 u1} (Prod.{u2, u1} G K) (Prod.instOneProd.{u2, u1} G K (InvOneClass.toOne.{u2} G (DivInvOneMonoid.toInvOneClass.{u2} G (DivisionMonoid.toDivInvOneMonoid.{u2} G (Group.toDivisionMonoid.{u2} G _inst_1)))) (InvOneClass.toOne.{u1} K (DivInvOneMonoid.toInvOneClass.{u1} K (DivisionMonoid.toDivInvOneMonoid.{u1} K (Group.toDivisionMonoid.{u1} K _inst_7))))))))) -> (Exists.{succ u2} (OpenSubgroup.{u2} G _inst_1 _inst_2) (fun (V : OpenSubgroup.{u2} G _inst_1 _inst_2) => Exists.{succ u1} (OpenSubgroup.{u1} K _inst_7 _inst_8) (fun (W : OpenSubgroup.{u1} K _inst_7 _inst_8) => HasSubset.Subset.{max u1 u2} (Set.{max u1 u2} (Prod.{u2, u1} G K)) (Set.instHasSubsetSet.{max u2 u1} (Prod.{u2, u1} G K)) (Set.prod.{u2, u1} G K (SetLike.coe.{u2, u2} (OpenSubgroup.{u2} G _inst_1 _inst_2) G (OpenSubgroup.instSetLikeOpenSubgroup.{u2} G _inst_1 _inst_2) V) (SetLike.coe.{u1, u1} (OpenSubgroup.{u1} K _inst_7 _inst_8) K (OpenSubgroup.instSetLikeOpenSubgroup.{u1} K _inst_7 _inst_8) W)) U)))
Case conversion may be inaccurate. Consider using '#align nonarchimedean_group.prod_subset NonarchimedeanGroup.prod_subsetₓ'. -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/-- An open neighborhood of the identity in the cartesian product of two nonarchimedean groups
contains the cartesian product of an open neighborhood in each group. -/
@[to_additive NonarchimedeanAddGroup.prod_subset
      "An open neighborhood of the identity in the\ncartesian product of two nonarchimedean groups contains the cartesian product of an open\nneighborhood in each group."]
theorem prod_subset {U} (hU : U ∈ nhds (1 : G × K)) :
    ∃ (V : OpenSubgroup G)(W : OpenSubgroup K), (V : Set G) ×ˢ (W : Set K) ⊆ U :=
  by
  erw [nhds_prod_eq, Filter.mem_prod_iff] at hU
  rcases hU with ⟨U₁, hU₁, U₂, hU₂, h⟩
  cases' is_nonarchimedean _ hU₁ with V hV
  cases' is_nonarchimedean _ hU₂ with W hW
  use V; use W
  rw [Set.prod_subset_iff]
  intro x hX y hY
  exact Set.Subset.trans (Set.prod_mono hV hW) h (Set.mem_sep hX hY)
#align nonarchimedean_group.prod_subset NonarchimedeanGroup.prod_subset
#align nonarchimedean_add_group.prod_subset NonarchimedeanAddGroup.prod_subset

/- warning: nonarchimedean_group.prod_self_subset -> NonarchimedeanGroup.prod_self_subset is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] [_inst_2 : TopologicalSpace.{u1} G] [_inst_3 : NonarchimedeanGroup.{u1} G _inst_1 _inst_2] {U : Set.{u1} (Prod.{u1, u1} G G)}, (Membership.Mem.{u1, u1} (Set.{u1} (Prod.{u1, u1} G G)) (Filter.{u1} (Prod.{u1, u1} G G)) (Filter.hasMem.{u1} (Prod.{u1, u1} G G)) U (nhds.{u1} (Prod.{u1, u1} G G) (Prod.topologicalSpace.{u1, u1} G G _inst_2 _inst_2) (OfNat.ofNat.{u1} (Prod.{u1, u1} G G) 1 (OfNat.mk.{u1} (Prod.{u1, u1} G G) 1 (One.one.{u1} (Prod.{u1, u1} G G) (Prod.hasOne.{u1, u1} G G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))))) -> (Exists.{succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (fun (V : OpenSubgroup.{u1} G _inst_1 _inst_2) => HasSubset.Subset.{u1} (Set.{u1} (Prod.{u1, u1} G G)) (Set.hasSubset.{u1} (Prod.{u1, u1} G G)) (Set.prod.{u1, u1} G G ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (HasLiftT.mk.{succ u1, succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (CoeTCₓ.coe.{succ u1, succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (SetLike.Set.hasCoeT.{u1, u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) G (OpenSubgroup.setLike.{u1} G _inst_1 _inst_2)))) V) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (HasLiftT.mk.{succ u1, succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (CoeTCₓ.coe.{succ u1, succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (Set.{u1} G) (SetLike.Set.hasCoeT.{u1, u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) G (OpenSubgroup.setLike.{u1} G _inst_1 _inst_2)))) V)) U))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] [_inst_2 : TopologicalSpace.{u1} G] [_inst_3 : NonarchimedeanGroup.{u1} G _inst_1 _inst_2] {U : Set.{u1} (Prod.{u1, u1} G G)}, (Membership.mem.{u1, u1} (Set.{u1} (Prod.{u1, u1} G G)) (Filter.{u1} (Prod.{u1, u1} G G)) (instMembershipSetFilter.{u1} (Prod.{u1, u1} G G)) U (nhds.{u1} (Prod.{u1, u1} G G) (instTopologicalSpaceProd.{u1, u1} G G _inst_2 _inst_2) (OfNat.ofNat.{u1} (Prod.{u1, u1} G G) 1 (One.toOfNat1.{u1} (Prod.{u1, u1} G G) (Prod.instOneProd.{u1, u1} G G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))) (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))))) -> (Exists.{succ u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) (fun (V : OpenSubgroup.{u1} G _inst_1 _inst_2) => HasSubset.Subset.{u1} (Set.{u1} (Prod.{u1, u1} G G)) (Set.instHasSubsetSet.{u1} (Prod.{u1, u1} G G)) (Set.prod.{u1, u1} G G (SetLike.coe.{u1, u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) G (OpenSubgroup.instSetLikeOpenSubgroup.{u1} G _inst_1 _inst_2) V) (SetLike.coe.{u1, u1} (OpenSubgroup.{u1} G _inst_1 _inst_2) G (OpenSubgroup.instSetLikeOpenSubgroup.{u1} G _inst_1 _inst_2) V)) U))
Case conversion may be inaccurate. Consider using '#align nonarchimedean_group.prod_self_subset NonarchimedeanGroup.prod_self_subsetₓ'. -/
/- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
/-- An open neighborhood of the identity in the cartesian square of a nonarchimedean group
contains the cartesian square of an open neighborhood in the group. -/
@[to_additive NonarchimedeanAddGroup.prod_self_subset
      "An open neighborhood of the identity in the\ncartesian square of a nonarchimedean group contains the cartesian square of an open neighborhood in\nthe group."]
theorem prod_self_subset {U} (hU : U ∈ nhds (1 : G × G)) :
    ∃ V : OpenSubgroup G, (V : Set G) ×ˢ (V : Set G) ⊆ U :=
  let ⟨V, W, h⟩ := prod_subset hU
  ⟨V ⊓ W, by refine' Set.Subset.trans (Set.prod_mono _ _) ‹_› <;> simp⟩
#align nonarchimedean_group.prod_self_subset NonarchimedeanGroup.prod_self_subset
#align nonarchimedean_add_group.prod_self_subset NonarchimedeanAddGroup.prod_self_subset

/-- The cartesian product of two nonarchimedean groups is nonarchimedean. -/
@[to_additive "The cartesian product of two nonarchimedean groups is nonarchimedean."]
instance : NonarchimedeanGroup (G × K)
    where is_nonarchimedean U hU :=
    let ⟨V, W, h⟩ := prod_subset hU
    ⟨V.Prod W, ‹_›⟩

end NonarchimedeanGroup

namespace NonarchimedeanRing

open NonarchimedeanRing

open NonarchimedeanAddGroup

variable {R S : Type _}

variable [Ring R] [TopologicalSpace R] [NonarchimedeanRing R]

variable [Ring S] [TopologicalSpace S] [NonarchimedeanRing S]

/-- The cartesian product of two nonarchimedean rings is nonarchimedean. -/
instance : NonarchimedeanRing (R × S)
    where is_nonarchimedean := NonarchimedeanAddGroup.is_nonarchimedean

/- warning: nonarchimedean_ring.left_mul_subset -> NonarchimedeanRing.left_mul_subset is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] [_inst_2 : TopologicalSpace.{u1} R] [_inst_3 : NonarchimedeanRing.{u1} R _inst_1 _inst_2] (U : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (r : R), Exists.{succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (fun (V : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) => HasSubset.Subset.{u1} (Set.{u1} R) (Set.hasSubset.{u1} R) (SMul.smul.{u1, u1} R (Set.{u1} R) (Set.smulSet.{u1, u1} R R (Mul.toSMul.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R _inst_1)))) r ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (HasLiftT.mk.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (CoeTCₓ.coe.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (SetLike.Set.hasCoeT.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) R (OpenAddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2)))) V)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (HasLiftT.mk.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (CoeTCₓ.coe.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (SetLike.Set.hasCoeT.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) R (OpenAddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2)))) U))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] [_inst_2 : TopologicalSpace.{u1} R] [_inst_3 : NonarchimedeanRing.{u1} R _inst_1 _inst_2] (U : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) (r : R), Exists.{succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) (fun (V : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) => HasSubset.Subset.{u1} (Set.{u1} R) (Set.instHasSubsetSet.{u1} R) (HSMul.hSMul.{u1, u1, u1} R (Set.{u1} R) (Set.{u1} R) (instHSMul.{u1, u1} R (Set.{u1} R) (Set.smulSet.{u1, u1} R R (SMulZeroClass.toSMul.{u1, u1} R R (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (SMulWithZero.toSMulZeroClass.{u1, u1} R R (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R (Ring.toSemiring.{u1} R _inst_1))) (MulZeroClass.toSMulWithZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))))))) r (SetLike.coe.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) R (OpenAddSubgroup.instSetLikeOpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) V)) (SetLike.coe.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) R (OpenAddSubgroup.instSetLikeOpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) U))
Case conversion may be inaccurate. Consider using '#align nonarchimedean_ring.left_mul_subset NonarchimedeanRing.left_mul_subsetₓ'. -/
/-- Given an open subgroup `U` and an element `r` of a nonarchimedean ring, there is an open
  subgroup `V` such that `r • V` is contained in `U`. -/
theorem left_mul_subset (U : OpenAddSubgroup R) (r : R) :
    ∃ V : OpenAddSubgroup R, r • (V : Set R) ⊆ U :=
  ⟨U.comap (AddMonoidHom.mulLeft r) (continuous_mul_left r), (U : Set R).image_preimage_subset _⟩
#align nonarchimedean_ring.left_mul_subset NonarchimedeanRing.left_mul_subset

/- warning: nonarchimedean_ring.mul_subset -> NonarchimedeanRing.mul_subset is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] [_inst_2 : TopologicalSpace.{u1} R] [_inst_3 : NonarchimedeanRing.{u1} R _inst_1 _inst_2] (U : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2), Exists.{succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (fun (V : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) => HasSubset.Subset.{u1} (Set.{u1} R) (Set.hasSubset.{u1} R) (HMul.hMul.{u1, u1, u1} (Set.{u1} R) (Set.{u1} R) (Set.{u1} R) (instHMul.{u1} (Set.{u1} R) (Set.mul.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R _inst_1)))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (HasLiftT.mk.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (CoeTCₓ.coe.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (SetLike.Set.hasCoeT.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) R (OpenAddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2)))) V) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (HasLiftT.mk.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (CoeTCₓ.coe.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (SetLike.Set.hasCoeT.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) R (OpenAddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2)))) V)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (HasLiftT.mk.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (CoeTCₓ.coe.{succ u1, succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) (Set.{u1} R) (SetLike.Set.hasCoeT.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2) R (OpenAddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_1))) _inst_2)))) U))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Ring.{u1} R] [_inst_2 : TopologicalSpace.{u1} R] [_inst_3 : NonarchimedeanRing.{u1} R _inst_1 _inst_2] (U : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2), Exists.{succ u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) (fun (V : OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) => HasSubset.Subset.{u1} (Set.{u1} R) (Set.instHasSubsetSet.{u1} R) (HMul.hMul.{u1, u1, u1} (Set.{u1} R) (Set.{u1} R) (Set.{u1} R) (instHMul.{u1} (Set.{u1} R) (Set.mul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_1))))) (SetLike.coe.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) R (OpenAddSubgroup.instSetLikeOpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) V) (SetLike.coe.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) R (OpenAddSubgroup.instSetLikeOpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) V)) (SetLike.coe.{u1, u1} (OpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) R (OpenAddSubgroup.instSetLikeOpenAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_1)) _inst_2) U))
Case conversion may be inaccurate. Consider using '#align nonarchimedean_ring.mul_subset NonarchimedeanRing.mul_subsetₓ'. -/
/-- An open subgroup of a nonarchimedean ring contains the square of another one. -/
theorem mul_subset (U : OpenAddSubgroup R) : ∃ V : OpenAddSubgroup R, (V : Set R) * V ⊆ U :=
  by
  let ⟨V, H⟩ :=
    prod_self_subset
      (IsOpen.mem_nhds (IsOpen.preimage continuous_mul U.IsOpen)
        (by
          simpa only [Set.mem_preimage, SetLike.mem_coe, Prod.snd_zero, MulZeroClass.mul_zero] using
            U.zero_mem))
  use V
  rintro v ⟨a, b, ha, hb, hv⟩
  have hy := H (Set.mk_mem_prod ha hb)
  simp only [Set.mem_preimage, SetLike.mem_coe] at hy
  rwa [hv] at hy
#align nonarchimedean_ring.mul_subset NonarchimedeanRing.mul_subset

end NonarchimedeanRing