/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.MinkowskiMetric
import HepLean.SpaceTime.LorentzVector.NormOne
/-!
# The Lorentz Group

We define the Lorentz group.

## References

- http://home.ku.edu.tr/~amostafazadeh/phys517_518/phys517_2016f/Handouts/A_Jaffi_Lorentz_Group.pdf

-/
/-! TODO: Show that the Lorentz is a Lie group. -/

noncomputable section

open Matrix
open Complex
open ComplexConjugate

/-!
## Matrices which preserves the Minkowski metric

We start studying the properties of matrices which preserve `ηLin`.
These matrices form the Lorentz group, which we will define in the next section at `lorentzGroup`.

-/
variable {d : ℕ}

open minkowskiMetric in
/-- The Lorentz group is the subset of matrices which preserve the minkowski metric. -/
def LorentzGroup (d : ℕ) : Set (Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ) :=
    {Λ : Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ |
      ∀ (x y : LorentzVector d), ⟪Λ *ᵥ x, Λ *ᵥ y⟫ₘ = ⟪x, y⟫ₘ}

namespace LorentzGroup
/-- Notation for the Lorentz group. -/
scoped[LorentzGroup] notation (name := lorentzGroup_notation) "𝓛" => LorentzGroup

open minkowskiMetric

variable {Λ Λ' : Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ}

/-!

# Membership conditions

-/

lemma mem_iff_norm : Λ ∈ LorentzGroup d ↔
    ∀ (x : LorentzVector d), ⟪Λ *ᵥ x, Λ *ᵥ x⟫ₘ = ⟪x, x⟫ₘ := by
  refine Iff.intro (fun h x => h x x) (fun h x y => ?_)
  have hp := h (x + y)
  have hn := h (x - y)
  rw [mulVec_add] at hp
  rw [mulVec_sub] at hn
  simp only [map_add, LinearMap.add_apply, map_sub, LinearMap.sub_apply] at hp hn
  rw [symm (Λ *ᵥ y) (Λ *ᵥ x), symm y x] at hp hn
  linear_combination hp / 4 + -1 * hn / 4

lemma mem_iff_on_right : Λ ∈ LorentzGroup d ↔
    ∀ (x y : LorentzVector d), ⟪x, (dual Λ * Λ) *ᵥ y⟫ₘ = ⟪x, y⟫ₘ := by
  refine Iff.intro (fun h x y ↦ ?_) (fun h x y ↦ ?_)
  · have h1 := h x y
    rw [← dual_mulVec_right, mulVec_mulVec] at h1
    exact h1
  · rw [← dual_mulVec_right, mulVec_mulVec]
    exact h x y

lemma mem_iff_dual_mul_self : Λ ∈ LorentzGroup d ↔ dual Λ * Λ = 1 := by
  rw [mem_iff_on_right, matrix_eq_id_iff]
  exact forall_comm

lemma mem_iff_self_mul_dual : Λ ∈ LorentzGroup d ↔ Λ * dual Λ = 1 := by
  rw [mem_iff_dual_mul_self]
  exact mul_eq_one_comm

lemma mem_iff_transpose : Λ ∈ LorentzGroup d ↔ Λᵀ ∈ LorentzGroup d := by
  refine Iff.intro (fun h ↦ ?_) (fun h ↦ ?_)
  · have h1 := congrArg transpose ((mem_iff_dual_mul_self).mp h)
    rw [dual, transpose_mul, transpose_mul, transpose_mul, minkowskiMatrix.eq_transpose,
      ← mul_assoc, transpose_one] at h1
    rw [mem_iff_self_mul_dual, ← h1, dual]
    noncomm_ring
  · have h1 := congrArg transpose ((mem_iff_dual_mul_self).mp h)
    rw [dual, transpose_mul, transpose_mul, transpose_mul, minkowskiMatrix.eq_transpose,
      ← mul_assoc, transpose_one, transpose_transpose] at h1
    rw [mem_iff_self_mul_dual, ← h1, dual]
    noncomm_ring

lemma mem_mul (hΛ : Λ ∈ LorentzGroup d) (hΛ' : Λ' ∈ LorentzGroup d) : Λ * Λ' ∈ LorentzGroup d := by
  rw [mem_iff_dual_mul_self, dual_mul]
  trans dual Λ' * (dual Λ * Λ) * Λ'
  · noncomm_ring
  · rw [(mem_iff_dual_mul_self).mp hΛ]
    simp [(mem_iff_dual_mul_self).mp hΛ']

lemma one_mem : 1 ∈ LorentzGroup d := by
  rw [mem_iff_dual_mul_self]
  simp

lemma dual_mem (h : Λ ∈ LorentzGroup d) : dual Λ ∈ LorentzGroup d := by
  rw [mem_iff_dual_mul_self, dual_dual]
  exact mem_iff_self_mul_dual.mp h

end LorentzGroup

/-!

# The Lorentz group as a group

-/

@[simps! mul_coe one_coe inv div]
instance lorentzGroupIsGroup : Group (LorentzGroup d) where
  mul A B := ⟨A.1 * B.1, LorentzGroup.mem_mul A.2 B.2⟩
  mul_assoc A B C := Subtype.eq (Matrix.mul_assoc A.1 B.1 C.1)
  one := ⟨1, LorentzGroup.one_mem⟩
  one_mul A := Subtype.eq (Matrix.one_mul A.1)
  mul_one A := Subtype.eq (Matrix.mul_one A.1)
  inv A := ⟨minkowskiMetric.dual A.1, LorentzGroup.dual_mem A.2⟩
  mul_left_inv A := Subtype.eq (LorentzGroup.mem_iff_dual_mul_self.mp A.2)

/-- `LorentzGroup` has the subtype topology. -/
instance : TopologicalSpace (LorentzGroup d) := instTopologicalSpaceSubtype

namespace LorentzGroup

open minkowskiMetric

variable {Λ Λ' : LorentzGroup d}

lemma coe_inv : (Λ⁻¹).1 = Λ.1⁻¹:= (inv_eq_left_inv (mem_iff_dual_mul_self.mp Λ.2)).symm

@[simp]
lemma subtype_inv_mul : (Subtype.val Λ)⁻¹ * (Subtype.val Λ) = 1 := by
  trans Subtype.val (Λ⁻¹ * Λ)
  · rw [← coe_inv]
    rfl
  · rw [mul_left_inv Λ]
    rfl

@[simp]
lemma subtype_mul_inv : (Subtype.val Λ) * (Subtype.val Λ)⁻¹ = 1 := by
  trans Subtype.val (Λ * Λ⁻¹)
  · rw [← coe_inv]
    rfl
  · rw [mul_right_inv Λ]
    rfl

@[simp]
lemma mul_minkowskiMatrix_mul_transpose :
    (Subtype.val Λ) * minkowskiMatrix * (Subtype.val Λ).transpose = minkowskiMatrix := by
  have h2 := Λ.prop
  rw [LorentzGroup.mem_iff_self_mul_dual] at h2
  simp only [dual] at h2
  refine (right_inv_eq_left_inv minkowskiMatrix.sq ?_).symm
  rw [← h2]
  noncomm_ring

@[simp]
lemma transpose_mul_minkowskiMatrix_mul_self :
    (Subtype.val Λ).transpose * minkowskiMatrix * (Subtype.val Λ) = minkowskiMatrix := by
  have h2 := Λ.prop
  rw [LorentzGroup.mem_iff_dual_mul_self] at h2
  simp only [dual] at h2
  refine right_inv_eq_left_inv ?_ minkowskiMatrix.sq
  rw [← h2]
  noncomm_ring

/-- The transpose of a matrix in the Lorentz group is an element of the Lorentz group. -/
def transpose (Λ : LorentzGroup d) : LorentzGroup d :=
  ⟨Λ.1ᵀ, mem_iff_transpose.mp Λ.2⟩

@[simp]
lemma transpose_one : @transpose d 1 = 1 := Subtype.eq Matrix.transpose_one

@[simp]
lemma transpose_mul : transpose (Λ * Λ') = transpose Λ' * transpose Λ :=
  Subtype.eq (Matrix.transpose_mul Λ.1 Λ'.1)

/-!

## Lorentz group as a topological group

We now show that the Lorentz group is a topological group.
We do this by showing that the natrual map from the Lorentz group to `GL (Fin 4) ℝ` is an
embedding.

-/

/-- The homomorphism of the Lorentz group into `GL (Fin 4) ℝ`. -/
def toGL : LorentzGroup d →* GL (Fin 1 ⊕ Fin d) ℝ where
  toFun A := ⟨A.1, (A⁻¹).1, mul_eq_one_comm.mpr $ mem_iff_dual_mul_self.mp A.2,
    mem_iff_dual_mul_self.mp A.2⟩
  map_one' :=
    (GeneralLinearGroup.ext_iff _ 1).mpr fun _ => congrFun rfl
  map_mul' _ _ :=
    (GeneralLinearGroup.ext_iff _ _).mpr fun _ => congrFun rfl

lemma toGL_injective : Function.Injective (@toGL d) := by
  refine fun A B h => Subtype.eq ?_
  rw [@Units.ext_iff] at h
  exact h

/-- The homomorphism from the Lorentz Group into the monoid of matrices times the opposite of
  the monoid of matrices. -/
@[simps!]
def toProd : LorentzGroup d →* (Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ) ×
    (Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ)ᵐᵒᵖ :=
  MonoidHom.comp (Units.embedProduct _) toGL

lemma toProd_eq_transpose_η : toProd Λ = (Λ.1, MulOpposite.op $ minkowskiMetric.dual Λ.1) := rfl

lemma toProd_injective : Function.Injective (@toProd d) := by
  intro A B h
  rw [toProd_eq_transpose_η, toProd_eq_transpose_η] at h
  rw [@Prod.mk.inj_iff] at h
  exact Subtype.eq h.1

lemma toProd_continuous : Continuous (@toProd d) := by
  change Continuous (fun A => (A.1, ⟨dual A.1⟩))
  refine continuous_prod_mk.mpr ⟨continuous_iff_le_induced.mpr fun U a ↦ a,
    MulOpposite.continuous_op.comp' ((continuous_const.matrix_mul (continuous_iff_le_induced.mpr
      fun U a => a).matrix_transpose).matrix_mul continuous_const)⟩

/-- The embedding from the Lorentz Group into the monoid of matrices times the opposite of
  the monoid of matrices. -/
lemma toProd_embedding : Embedding (@toProd d) where
  inj := toProd_injective
  induced :=
    (inducing_iff ⇑toProd).mp (inducing_of_inducing_compose toProd_continuous continuous_fst
      ((inducing_iff (Prod.fst ∘ ⇑toProd)).mpr rfl))

/-- The embedding from the Lorentz Group into `GL (Fin 4) ℝ`. -/
lemma toGL_embedding : Embedding (@toGL d).toFun where
  inj := toGL_injective
  induced := by
    refine ((fun {X} {t t'} => TopologicalSpace.ext_iff.mpr) fun _ ↦ ?_).symm
    rw [TopologicalSpace.ext_iff.mp toProd_embedding.induced _, isOpen_induced_iff,
      isOpen_induced_iff]
    exact exists_exists_and_eq_and

instance : TopologicalGroup (LorentzGroup d) :=
Inducing.topologicalGroup toGL toGL_embedding.toInducing

section
open LorentzVector
/-!

# To a norm one Lorentz vector

-/

/-- The first column of a Lorentz matrix as a `NormOneLorentzVector`. -/
@[simps!]
def toNormOneLorentzVector (Λ : LorentzGroup d) : NormOneLorentzVector d :=
  ⟨Λ.1 *ᵥ timeVec, by rw [NormOneLorentzVector.mem_iff, Λ.2, minkowskiMetric.on_timeVec]⟩

/-!

# The time like element

-/

/-- The time like element of a Lorentz matrix. -/
@[simp]
def timeComp (Λ : LorentzGroup d) : ℝ := Λ.1 (Sum.inl 0) (Sum.inl 0)

theorem _root_.Matrix.mulVec_single_one [Fintype n] [DecidableEq n] [NonAssocSemiring R]
    (M : Matrix m n R) (j : n) :
    M *ᵥ Pi.single j 1 = Mᵀ j := by ext; simp

lemma timeComp_eq_toNormOneLorentzVector : timeComp Λ = (toNormOneLorentzVector Λ).1.time

:= by
  simp only [time, toNormOneLorentzVector, timeVec, Fin.isValue, timeComp]
  erw [Pi.basisFun_apply, Matrix.mulVec_single_one]
  rfl


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.MinkowskiMetric
import HepLean.SpaceTime.LorentzVector.NormOne
/-!
# The Lorentz Group

We define the Lorentz group.

## References

- http://home.ku.edu.tr/~amostafazadeh/phys517_518/phys517_2016f/Handouts/A_Jaffi_Lorentz_Group.pdf

-/
/-! TODO: Show that the Lorentz is a Lie group. -/

noncomputable section

open Matrix
open Complex
open ComplexConjugate

/-!
## Matrices which preserves the Minkowski metric

We start studying the properties of matrices which preserve `ηLin`.
These matrices form the Lorentz group, which we will define in the next section at `lorentzGroup`.

-/
variable {d : ℕ}

open minkowskiMetric in
/-- The Lorentz group is the subset of matrices which preserve the minkowski metric. -/
def LorentzGroup (d : ℕ) : Set (Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ) :=
    {Λ : Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ |
      ∀ (x y : LorentzVector d), ⟪Λ *ᵥ x, Λ *ᵥ y⟫ₘ = ⟪x, y⟫ₘ}

namespace LorentzGroup
/-- Notation for the Lorentz group. -/
scoped[LorentzGroup] notation (name := lorentzGroup_notation) "𝓛" => LorentzGroup

open minkowskiMetric

variable {Λ Λ' : Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ}

/-!

# Membership conditions

-/

lemma mem_iff_norm : Λ ∈ LorentzGroup d ↔
    ∀ (x : LorentzVector d), ⟪Λ *ᵥ x, Λ *ᵥ x⟫ₘ = ⟪x, x⟫ₘ := by
  refine Iff.intro (fun h x => h x x) (fun h x y => ?_)
  have hp := h (x + y)
  have hn := h (x - y)
  rw [mulVec_add] at hp
  rw [mulVec_sub] at hn
  simp only [map_add, LinearMap.add_apply, map_sub, LinearMap.sub_apply] at hp hn
  rw [symm (Λ *ᵥ y) (Λ *ᵥ x), symm y x] at hp hn
  linear_combination hp / 4 + -1 * hn / 4

lemma mem_iff_on_right : Λ ∈ LorentzGroup d ↔
    ∀ (x y : LorentzVector d), ⟪x, (dual Λ * Λ) *ᵥ y⟫ₘ = ⟪x, y⟫ₘ := by
  refine Iff.intro (fun h x y ↦ ?_) (fun h x y ↦ ?_)
  · have h1 := h x y
    rw [← dual_mulVec_right, mulVec_mulVec] at h1
    exact h1
  · rw [← dual_mulVec_right, mulVec_mulVec]
    exact h x y

lemma mem_iff_dual_mul_self : Λ ∈ LorentzGroup d ↔ dual Λ * Λ = 1 := by
  rw [mem_iff_on_right, matrix_eq_id_iff]
  exact forall_comm

lemma mem_iff_self_mul_dual : Λ ∈ LorentzGroup d ↔ Λ * dual Λ = 1 := by
  rw [mem_iff_dual_mul_self]
  exact mul_eq_one_comm

lemma mem_iff_transpose : Λ ∈ LorentzGroup d ↔ Λᵀ ∈ LorentzGroup d := by
  refine Iff.intro (fun h ↦ ?_) (fun h ↦ ?_)
  · have h1 := congrArg transpose ((mem_iff_dual_mul_self).mp h)
    rw [dual, transpose_mul, transpose_mul, transpose_mul, minkowskiMatrix.eq_transpose,
      ← mul_assoc, transpose_one] at h1
    rw [mem_iff_self_mul_dual, ← h1, dual]
    noncomm_ring
  · have h1 := congrArg transpose ((mem_iff_dual_mul_self).mp h)
    rw [dual, transpose_mul, transpose_mul, transpose_mul, minkowskiMatrix.eq_transpose,
      ← mul_assoc, transpose_one, transpose_transpose] at h1
    rw [mem_iff_self_mul_dual, ← h1, dual]
    noncomm_ring

lemma mem_mul (hΛ : Λ ∈ LorentzGroup d) (hΛ' : Λ' ∈ LorentzGroup d) : Λ * Λ' ∈ LorentzGroup d := by
  rw [mem_iff_dual_mul_self, dual_mul]
  trans dual Λ' * (dual Λ * Λ) * Λ'
  · noncomm_ring
  · rw [(mem_iff_dual_mul_self).mp hΛ]
    simp [(mem_iff_dual_mul_self).mp hΛ']

lemma one_mem : 1 ∈ LorentzGroup d := by
  rw [mem_iff_dual_mul_self]
  simp

lemma dual_mem (h : Λ ∈ LorentzGroup d) : dual Λ ∈ LorentzGroup d := by
  rw [mem_iff_dual_mul_self, dual_dual]
  exact mem_iff_self_mul_dual.mp h

end LorentzGroup

/-!

# The Lorentz group as a group

-/

@[simps! mul_coe one_coe inv div]
instance lorentzGroupIsGroup : Group (LorentzGroup d) where
  mul A B := ⟨A.1 * B.1, LorentzGroup.mem_mul A.2 B.2⟩
  mul_assoc A B C := Subtype.eq (Matrix.mul_assoc A.1 B.1 C.1)
  one := ⟨1, LorentzGroup.one_mem⟩
  one_mul A := Subtype.eq (Matrix.one_mul A.1)
  mul_one A := Subtype.eq (Matrix.mul_one A.1)
  inv A := ⟨minkowskiMetric.dual A.1, LorentzGroup.dual_mem A.2⟩
  mul_left_inv A := Subtype.eq (LorentzGroup.mem_iff_dual_mul_self.mp A.2)

/-- `LorentzGroup` has the subtype topology. -/
instance : TopologicalSpace (LorentzGroup d) := instTopologicalSpaceSubtype

namespace LorentzGroup

open minkowskiMetric

variable {Λ Λ' : LorentzGroup d}

lemma coe_inv : (Λ⁻¹).1 = Λ.1⁻¹:= (inv_eq_left_inv (mem_iff_dual_mul_self.mp Λ.2)).symm

@[simp]
lemma subtype_inv_mul : (Subtype.val Λ)⁻¹ * (Subtype.val Λ) = 1 := by
  trans Subtype.val (Λ⁻¹ * Λ)
  · rw [← coe_inv]
    rfl
  · rw [mul_left_inv Λ]
    rfl

@[simp]
lemma subtype_mul_inv : (Subtype.val Λ) * (Subtype.val Λ)⁻¹ = 1 := by
  trans Subtype.val (Λ * Λ⁻¹)
  · rw [← coe_inv]
    rfl
  · rw [mul_right_inv Λ]
    rfl

@[simp]
lemma mul_minkowskiMatrix_mul_transpose :
    (Subtype.val Λ) * minkowskiMatrix * (Subtype.val Λ).transpose = minkowskiMatrix := by
  have h2 := Λ.prop
  rw [LorentzGroup.mem_iff_self_mul_dual] at h2
  simp only [dual] at h2
  refine (right_inv_eq_left_inv minkowskiMatrix.sq ?_).symm
  rw [← h2]
  noncomm_ring

@[simp]
lemma transpose_mul_minkowskiMatrix_mul_self :
    (Subtype.val Λ).transpose * minkowskiMatrix * (Subtype.val Λ) = minkowskiMatrix := by
  have h2 := Λ.prop
  rw [LorentzGroup.mem_iff_dual_mul_self] at h2
  simp only [dual] at h2
  refine right_inv_eq_left_inv ?_ minkowskiMatrix.sq
  rw [← h2]
  noncomm_ring

/-- The transpose of a matrix in the Lorentz group is an element of the Lorentz group. -/
def transpose (Λ : LorentzGroup d) : LorentzGroup d :=
  ⟨Λ.1ᵀ, mem_iff_transpose.mp Λ.2⟩

@[simp]
lemma transpose_one : @transpose d 1 = 1 := Subtype.eq Matrix.transpose_one

@[simp]
lemma transpose_mul : transpose (Λ * Λ') = transpose Λ' * transpose Λ :=
  Subtype.eq (Matrix.transpose_mul Λ.1 Λ'.1)

/-!

## Lorentz group as a topological group

We now show that the Lorentz group is a topological group.
We do this by showing that the natrual map from the Lorentz group to `GL (Fin 4) ℝ` is an
embedding.

-/

/-- The homomorphism of the Lorentz group into `GL (Fin 4) ℝ`. -/
def toGL : LorentzGroup d →* GL (Fin 1 ⊕ Fin d) ℝ where
  toFun A := ⟨A.1, (A⁻¹).1, mul_eq_one_comm.mpr $ mem_iff_dual_mul_self.mp A.2,
    mem_iff_dual_mul_self.mp A.2⟩
  map_one' :=
    (GeneralLinearGroup.ext_iff _ 1).mpr fun _ => congrFun rfl
  map_mul' _ _ :=
    (GeneralLinearGroup.ext_iff _ _).mpr fun _ => congrFun rfl

lemma toGL_injective : Function.Injective (@toGL d) := by
  refine fun A B h => Subtype.eq ?_
  rw [@Units.ext_iff] at h
  exact h

/-- The homomorphism from the Lorentz Group into the monoid of matrices times the opposite of
  the monoid of matrices. -/
@[simps!]
def toProd : LorentzGroup d →* (Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ) ×
    (Matrix (Fin 1 ⊕ Fin d) (Fin 1 ⊕ Fin d) ℝ)ᵐᵒᵖ :=
  MonoidHom.comp (Units.embedProduct _) toGL

lemma toProd_eq_transpose_η : toProd Λ = (Λ.1, MulOpposite.op $ minkowskiMetric.dual Λ.1) := rfl

lemma toProd_injective : Function.Injective (@toProd d) := by
  intro A B h
  rw [toProd_eq_transpose_η, toProd_eq_transpose_η] at h
  rw [@Prod.mk.inj_iff] at h
  exact Subtype.eq h.1

lemma toProd_continuous : Continuous (@toProd d) := by
  change Continuous (fun A => (A.1, ⟨dual A.1⟩))
  refine continuous_prod_mk.mpr ⟨continuous_iff_le_induced.mpr fun U a ↦ a,
    MulOpposite.continuous_op.comp' ((continuous_const.matrix_mul (continuous_iff_le_induced.mpr
      fun U a => a).matrix_transpose).matrix_mul continuous_const)⟩

/-- The embedding from the Lorentz Group into the monoid of matrices times the opposite of
  the monoid of matrices. -/
lemma toProd_embedding : Embedding (@toProd d) where
  inj := toProd_injective
  induced :=
    (inducing_iff ⇑toProd).mp (inducing_of_inducing_compose toProd_continuous continuous_fst
      ((inducing_iff (Prod.fst ∘ ⇑toProd)).mpr rfl))

/-- The embedding from the Lorentz Group into `GL (Fin 4) ℝ`. -/
lemma toGL_embedding : Embedding (@toGL d).toFun where
  inj := toGL_injective
  induced := by
    refine ((fun {X} {t t'} => TopologicalSpace.ext_iff.mpr) fun _ ↦ ?_).symm
    rw [TopologicalSpace.ext_iff.mp toProd_embedding.induced _, isOpen_induced_iff,
      isOpen_induced_iff]
    exact exists_exists_and_eq_and

instance : TopologicalGroup (LorentzGroup d) :=
Inducing.topologicalGroup toGL toGL_embedding.toInducing

section
open LorentzVector
/-!

# To a norm one Lorentz vector

-/

/-- The first column of a Lorentz matrix as a `NormOneLorentzVector`. -/
@[simps!]
def toNormOneLorentzVector (Λ : LorentzGroup d) : NormOneLorentzVector d :=
  ⟨Λ.1 *ᵥ timeVec, by rw [NormOneLorentzVector.mem_iff, Λ.2, minkowskiMetric.on_timeVec]⟩

/-!

# The time like element

-/

/-- The time like element of a Lorentz matrix. -/
@[simp]
def timeComp (Λ : LorentzGroup d) : ℝ := Λ.1 (Sum.inl 0) (Sum.inl 0)

theorem _root_.Matrix.mulVec_single_one [Fintype n] [DecidableEq n] [NonAssocSemiring R]
    (M : Matrix m n R) (j : n) :
    M *ᵥ Pi.single j 1 = Mᵀ j := by ext; simp

lemma timeComp_eq_toNormOneLorentzVector : timeComp Λ = (toNormOneLorentzVector Λ).1.time := by
  simp only [time, toNormOneLorentzVector, timeVec, Fin.isValue, timeComp]
  erw [Pi.basisFun_apply, Matrix.mulVec_single_one]
  rfl

lemma timeComp_mul (Λ Λ' : LorentzGroup d) : timeComp (Λ * Λ') =
    ⟪toNormOneLorentzVector (transpose Λ), (toNormOneLorentzVector Λ').1.spaceReflection⟫ₘ

:= by
  simp only [timeComp, Fin.isValue, lorentzGroupIsGroup_mul_coe, mul_apply, Fintype.sum_sum_type,
    Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton, toNormOneLorentzVector,
    transpose, timeVec, right_spaceReflection, time, space, PiLp.inner_apply, Function.comp_apply,
    RCLike.inner_apply, conj_trivial]
  erw [Pi.basisFun_apply, Matrix.mulVec_single_one]
  simp


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.Tensors.IndexNotation.TensorIndex
import HepLean.Tensors.IndexNotation.IndexString
import HepLean.SpaceTime.LorentzTensor.Real.Basic
/-!

# Index notation for real Lorentz tensors

This uses the general concepts of index notation in `HepLean.SpaceTime.LorentzTensor.IndexNotation`
to define the index notation for real Lorentz tensors.

-/

instance : IndexNotation realTensorColor.Color where
  charList := {'ᵘ', 'ᵤ'}
  notaEquiv :=
    ⟨fun c =>
      match c with
      | realTensorColor.ColorType.up => ⟨'ᵘ', Finset.mem_insert_self 'ᵘ' {'ᵤ'}⟩
      | realTensorColor.ColorType.down => ⟨'ᵤ', Finset.insert_eq_self.mp (by rfl)⟩,
    fun c =>
      if c = 'ᵘ' then realTensorColor.ColorType.up
      else realTensorColor.ColorType.down,
    by
      intro c
      match c with
      | realTensorColor.ColorType.up => rfl
      | realTensorColor.ColorType.down => rfl,
    by
      intro c
      by_cases hc : c = 'ᵘ'
      · simp only [↓Char.isValue, hc, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc))
      · have hc' : c = 'ᵤ' := by
          have hc2 := c.2
          simp only [↓Char.isValue, Finset.mem_insert, Finset.mem_singleton] at hc2
          simp_all
        simp only [↓Char.isValue, hc', Char.reduceEq, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc'))⟩

namespace realLorentzTensor

open realTensorColor
open IndexNotation IndexString
open TensorStructure TensorIndex

variable {d : ℕ}

instance instIndexNotationColor : IndexNotation (realLorentzTensor d).Color := instIndexNotationColorRealTensorColor
instance instDecidableEqColor : DecidableEq (realLorentzTensor d).Color := instDecidableEqColorRealTensorColor

@[simp]
lemma indexNotation_eq_color : @realLorentzTensor.instIndexNotationColor d =
    instIndexNotationColorRealTensorColor


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.Tensors.IndexNotation.TensorIndex
import HepLean.Tensors.IndexNotation.IndexString
import HepLean.SpaceTime.LorentzTensor.Real.Basic
/-!

# Index notation for real Lorentz tensors

This uses the general concepts of index notation in `HepLean.SpaceTime.LorentzTensor.IndexNotation`
to define the index notation for real Lorentz tensors.

-/

instance : IndexNotation realTensorColor.Color where
  charList := {'ᵘ', 'ᵤ'}
  notaEquiv :=
    ⟨fun c =>
      match c with
      | realTensorColor.ColorType.up => ⟨'ᵘ', Finset.mem_insert_self 'ᵘ' {'ᵤ'}⟩
      | realTensorColor.ColorType.down => ⟨'ᵤ', Finset.insert_eq_self.mp (by rfl)⟩,
    fun c =>
      if c = 'ᵘ' then realTensorColor.ColorType.up
      else realTensorColor.ColorType.down,
    by
      intro c
      match c with
      | realTensorColor.ColorType.up => rfl
      | realTensorColor.ColorType.down => rfl,
    by
      intro c
      by_cases hc : c = 'ᵘ'
      · simp only [↓Char.isValue, hc, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc))
      · have hc' : c = 'ᵤ' := by
          have hc2 := c.2
          simp only [↓Char.isValue, Finset.mem_insert, Finset.mem_singleton] at hc2
          simp_all
        simp only [↓Char.isValue, hc', Char.reduceEq, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc'))⟩

namespace realLorentzTensor

open realTensorColor
open IndexNotation IndexString
open TensorStructure TensorIndex

variable {d : ℕ}

instance instIndexNotationColor : IndexNotation (realLorentzTensor d).Color := instIndexNotationColorRealTensorColor
instance instDecidableEqColor : DecidableEq (realLorentzTensor d).Color := instDecidableEqColorRealTensorColor

@[simp]
lemma indexNotation_eq_color : @realLorentzTensor.instIndexNotationColor d =
    instIndexNotationColorRealTensorColor := by
  rfl

@[simp]
lemma decidableEq_eq_color : @realLorentzTensor.instDecidableEqColor d =
    instDecidableEqColorRealTensorColor


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.Tensors.IndexNotation.TensorIndex
import HepLean.Tensors.IndexNotation.IndexString
import HepLean.SpaceTime.LorentzTensor.Real.Basic
/-!

# Index notation for real Lorentz tensors

This uses the general concepts of index notation in `HepLean.SpaceTime.LorentzTensor.IndexNotation`
to define the index notation for real Lorentz tensors.

-/

instance : IndexNotation realTensorColor.Color where
  charList := {'ᵘ', 'ᵤ'}
  notaEquiv :=
    ⟨fun c =>
      match c with
      | realTensorColor.ColorType.up => ⟨'ᵘ', Finset.mem_insert_self 'ᵘ' {'ᵤ'}⟩
      | realTensorColor.ColorType.down => ⟨'ᵤ', Finset.insert_eq_self.mp (by rfl)⟩,
    fun c =>
      if c = 'ᵘ' then realTensorColor.ColorType.up
      else realTensorColor.ColorType.down,
    by
      intro c
      match c with
      | realTensorColor.ColorType.up => rfl
      | realTensorColor.ColorType.down => rfl,
    by
      intro c
      by_cases hc : c = 'ᵘ'
      · simp only [↓Char.isValue, hc, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc))
      · have hc' : c = 'ᵤ' := by
          have hc2 := c.2
          simp only [↓Char.isValue, Finset.mem_insert, Finset.mem_singleton] at hc2
          simp_all
        simp only [↓Char.isValue, hc', Char.reduceEq, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc'))⟩

namespace realLorentzTensor

open realTensorColor
open IndexNotation IndexString
open TensorStructure TensorIndex

variable {d : ℕ}

instance instIndexNotationColor : IndexNotation (realLorentzTensor d).Color := instIndexNotationColorRealTensorColor
instance instDecidableEqColor : DecidableEq (realLorentzTensor d).Color := instDecidableEqColorRealTensorColor

@[simp]
lemma indexNotation_eq_color : @realLorentzTensor.instIndexNotationColor d =
    instIndexNotationColorRealTensorColor := by
  rfl

@[simp]
lemma decidableEq_eq_color : @realLorentzTensor.instDecidableEqColor d =
    instDecidableEqColorRealTensorColor := by
  rfl

@[simp]
lemma realLorentzTensor_color : (realLorentzTensor d).Color = realTensorColor.Color


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.Tensors.IndexNotation.TensorIndex
import HepLean.Tensors.IndexNotation.IndexString
import HepLean.SpaceTime.LorentzTensor.Real.Basic
/-!

# Index notation for real Lorentz tensors

This uses the general concepts of index notation in `HepLean.SpaceTime.LorentzTensor.IndexNotation`
to define the index notation for real Lorentz tensors.

-/

instance : IndexNotation realTensorColor.Color where
  charList := {'ᵘ', 'ᵤ'}
  notaEquiv :=
    ⟨fun c =>
      match c with
      | realTensorColor.ColorType.up => ⟨'ᵘ', Finset.mem_insert_self 'ᵘ' {'ᵤ'}⟩
      | realTensorColor.ColorType.down => ⟨'ᵤ', Finset.insert_eq_self.mp (by rfl)⟩,
    fun c =>
      if c = 'ᵘ' then realTensorColor.ColorType.up
      else realTensorColor.ColorType.down,
    by
      intro c
      match c with
      | realTensorColor.ColorType.up => rfl
      | realTensorColor.ColorType.down => rfl,
    by
      intro c
      by_cases hc : c = 'ᵘ'
      · simp only [↓Char.isValue, hc, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc))
      · have hc' : c = 'ᵤ' := by
          have hc2 := c.2
          simp only [↓Char.isValue, Finset.mem_insert, Finset.mem_singleton] at hc2
          simp_all
        simp only [↓Char.isValue, hc', Char.reduceEq, ↓reduceIte]
        exact SetCoe.ext (id (Eq.symm hc'))⟩

namespace realLorentzTensor

open realTensorColor
open IndexNotation IndexString
open TensorStructure TensorIndex

variable {d : ℕ}

instance instIndexNotationColor : IndexNotation (realLorentzTensor d).Color := instIndexNotationColorRealTensorColor
instance instDecidableEqColor : DecidableEq (realLorentzTensor d).Color := instDecidableEqColorRealTensorColor

@[simp]
lemma indexNotation_eq_color : @realLorentzTensor.instIndexNotationColor d =
    instIndexNotationColorRealTensorColor := by
  rfl

@[simp]
lemma decidableEq_eq_color : @realLorentzTensor.instDecidableEqColor d =
    instDecidableEqColorRealTensorColor := by
  rfl

@[simp]
lemma realLorentzTensor_color : (realLorentzTensor d).Color = realTensorColor.Color := by
  rfl

@[simp]
lemma toTensorColor_eq : (realLorentzTensor d).toTensorColor = realTensorColor


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0

:= by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0 := by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']

lemma decomp_stdBasis (v : LorentzVector d) : ∑ i, v i • e i = v

:= by
  funext ν
  rw [Finset.sum_apply]
  rw [Finset.sum_eq_single_of_mem ν]
  · simp only [HSMul.hSMul, SMul.smul, stdBasis]
    erw [Pi.basisFun_apply]
    simp only [LinearMap.stdBasis_apply', ↓reduceIte, mul_one]
  · exact Finset.mem_univ ν
  · intros b _ hbi
    simp only [HSMul.hSMul, SMul.smul, stdBasis, mul_eq_zero]
    erw [Pi.basisFun_apply]
    simp only [Pi.single]
    apply Or.inr $ Function.update_noteq (id (Ne.symm hbi)) 1 0


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0 := by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']

lemma decomp_stdBasis (v : LorentzVector d) : ∑ i, v i • e i = v := by
  funext ν
  rw [Finset.sum_apply]
  rw [Finset.sum_eq_single_of_mem ν]
  · simp only [HSMul.hSMul, SMul.smul, stdBasis]
    erw [Pi.basisFun_apply]
    simp only [LinearMap.stdBasis_apply', ↓reduceIte, mul_one]
  · exact Finset.mem_univ ν
  · intros b _ hbi
    simp only [HSMul.hSMul, SMul.smul, stdBasis, mul_eq_zero]
    erw [Pi.basisFun_apply]
    simp only [Pi.single]
    apply Or.inr $ Function.update_noteq (id (Ne.symm hbi)) 1 0

@[simp]
lemma decomp_stdBasis' (v : LorentzVector d) :
    v (Sum.inl 0) • e (Sum.inl 0) + ∑ a₂ : Fin d, v (Sum.inr a₂) • e (Sum.inr a₂) = v

:= by
  trans ∑ i, v i • e i
  · simp only [Fin.isValue, Fintype.sum_sum_type, Finset.univ_unique, Fin.default_eq_zero,
      Finset.sum_singleton]
  · exact decomp_stdBasis v


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0 := by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']

lemma decomp_stdBasis (v : LorentzVector d) : ∑ i, v i • e i = v := by
  funext ν
  rw [Finset.sum_apply]
  rw [Finset.sum_eq_single_of_mem ν]
  · simp only [HSMul.hSMul, SMul.smul, stdBasis]
    erw [Pi.basisFun_apply]
    simp only [LinearMap.stdBasis_apply', ↓reduceIte, mul_one]
  · exact Finset.mem_univ ν
  · intros b _ hbi
    simp only [HSMul.hSMul, SMul.smul, stdBasis, mul_eq_zero]
    erw [Pi.basisFun_apply]
    simp only [Pi.single]
    apply Or.inr $ Function.update_noteq (id (Ne.symm hbi)) 1 0

@[simp]
lemma decomp_stdBasis' (v : LorentzVector d) :
    v (Sum.inl 0) • e (Sum.inl 0) + ∑ a₂ : Fin d, v (Sum.inr a₂) • e (Sum.inr a₂) = v := by
  trans ∑ i, v i • e i
  · simp only [Fin.isValue, Fintype.sum_sum_type, Finset.univ_unique, Fin.default_eq_zero,
      Finset.sum_singleton]
  · exact decomp_stdBasis v

/-- The standard unit time vector. -/
noncomputable abbrev timeVec : (LorentzVector d) := e (Sum.inl 0)

lemma timeVec_space : (@timeVec d).space = 0

:= by
  funext i
  simp only [space, Function.comp_apply, stdBasis_apply, Fin.isValue, ↓reduceIte, PiLp.zero_apply]


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0 := by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']

lemma decomp_stdBasis (v : LorentzVector d) : ∑ i, v i • e i = v := by
  funext ν
  rw [Finset.sum_apply]
  rw [Finset.sum_eq_single_of_mem ν]
  · simp only [HSMul.hSMul, SMul.smul, stdBasis]
    erw [Pi.basisFun_apply]
    simp only [LinearMap.stdBasis_apply', ↓reduceIte, mul_one]
  · exact Finset.mem_univ ν
  · intros b _ hbi
    simp only [HSMul.hSMul, SMul.smul, stdBasis, mul_eq_zero]
    erw [Pi.basisFun_apply]
    simp only [Pi.single]
    apply Or.inr $ Function.update_noteq (id (Ne.symm hbi)) 1 0

@[simp]
lemma decomp_stdBasis' (v : LorentzVector d) :
    v (Sum.inl 0) • e (Sum.inl 0) + ∑ a₂ : Fin d, v (Sum.inr a₂) • e (Sum.inr a₂) = v := by
  trans ∑ i, v i • e i
  · simp only [Fin.isValue, Fintype.sum_sum_type, Finset.univ_unique, Fin.default_eq_zero,
      Finset.sum_singleton]
  · exact decomp_stdBasis v

/-- The standard unit time vector. -/
noncomputable abbrev timeVec : (LorentzVector d) := e (Sum.inl 0)

lemma timeVec_space : (@timeVec d).space = 0 := by
  funext i
  simp only [space, Function.comp_apply, stdBasis_apply, Fin.isValue, ↓reduceIte, PiLp.zero_apply]

lemma timeVec_time: (@timeVec d).time = 1

:= by
  simp only [time, Fin.isValue, stdBasis_apply, ↓reduceIte]


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0 := by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']

lemma decomp_stdBasis (v : LorentzVector d) : ∑ i, v i • e i = v := by
  funext ν
  rw [Finset.sum_apply]
  rw [Finset.sum_eq_single_of_mem ν]
  · simp only [HSMul.hSMul, SMul.smul, stdBasis]
    erw [Pi.basisFun_apply]
    simp only [LinearMap.stdBasis_apply', ↓reduceIte, mul_one]
  · exact Finset.mem_univ ν
  · intros b _ hbi
    simp only [HSMul.hSMul, SMul.smul, stdBasis, mul_eq_zero]
    erw [Pi.basisFun_apply]
    simp only [Pi.single]
    apply Or.inr $ Function.update_noteq (id (Ne.symm hbi)) 1 0

@[simp]
lemma decomp_stdBasis' (v : LorentzVector d) :
    v (Sum.inl 0) • e (Sum.inl 0) + ∑ a₂ : Fin d, v (Sum.inr a₂) • e (Sum.inr a₂) = v := by
  trans ∑ i, v i • e i
  · simp only [Fin.isValue, Fintype.sum_sum_type, Finset.univ_unique, Fin.default_eq_zero,
      Finset.sum_singleton]
  · exact decomp_stdBasis v

/-- The standard unit time vector. -/
noncomputable abbrev timeVec : (LorentzVector d) := e (Sum.inl 0)

lemma timeVec_space : (@timeVec d).space = 0 := by
  funext i
  simp only [space, Function.comp_apply, stdBasis_apply, Fin.isValue, ↓reduceIte, PiLp.zero_apply]

lemma timeVec_time: (@timeVec d).time = 1 := by
  simp only [time, Fin.isValue, stdBasis_apply, ↓reduceIte]

/-!

# Reflection of space

-/

/-- The reflection of space as a linear map. -/
@[simps!]
def spaceReflectionLin : LorentzVector d →ₗ[ℝ] LorentzVector d where
  toFun x := Sum.elim (x ∘ Sum.inl) (- x ∘ Sum.inr)
  map_add' x y := by
    funext i
    rcases i with i | i
    · rfl
    · simp only [Sum.elim_inr, Pi.neg_apply]
      apply neg_add
  map_smul' c x := by
    funext i
    rcases i with i | i
    · rfl
    · simp [HSMul.hSMul, SMul.smul]

/-- The reflection of space. -/
@[simp]
def spaceReflection : LorentzVector d := spaceReflectionLin v

lemma spaceReflection_space : v.spaceReflection.space = - v.space


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Complex.Exponential
import Mathlib.Analysis.InnerProductSpace.PiL2
/-!

# Lorentz vectors

(aka 4-vectors)

In this file we define a Lorentz vector (in 4d, this is more often called a 4-vector).

One of the most important example of a Lorentz vector is SpaceTime.

We will define the group action of the Lorentz group on Lorentz vectors in
`HepLean.SpaceTime.LorentzVector.LorentzAction` in such a way that `LorentzVector`
corresponds to contravariant Lorentz tensors.

-/

open BigOperators

/- The number of space dimensions . -/
variable (d : ℕ)

/-- The type of (contravariant) Lorentz Vectors in `d`-space dimensions. -/
def LorentzVector : Type := (Fin 1 ⊕ Fin d) → ℝ

/-- An instance of an additive commutative monoid on `LorentzVector`. -/
instance : AddCommMonoid (LorentzVector d) := Pi.addCommMonoid

/-- An instance of a module on `LorentzVector`. -/
noncomputable instance instModuleRealLorentzVector : Module ℝ (LorentzVector d) := Pi.module _ _ _

instance : AddCommGroup (LorentzVector d) := Pi.addCommGroup

/-- The structure of a topological space `LorentzVector d`. -/
instance : TopologicalSpace (LorentzVector d) :=
  haveI : NormedAddCommGroup (LorentzVector d) := Pi.normedAddCommGroup
  UniformSpace.toTopologicalSpace

namespace LorentzVector

variable {d : ℕ} (v : LorentzVector d)

/-- The space components. -/
@[simp]
def space : EuclideanSpace ℝ (Fin d) := v ∘ Sum.inr

/-- The time component. -/
@[simp]
def time : ℝ := v (Sum.inl 0)

/-!

# The standard basis

-/

/-- The standard basis of `LorentzVector` indexed by `Fin 1 ⊕ Fin (d)`. -/
@[simps!]
noncomputable def stdBasis : Basis (Fin 1 ⊕ Fin (d)) ℝ (LorentzVector d) := Pi.basisFun ℝ _

/-- Notation for `stdBasis`. -/
scoped[LorentzVector] notation "e" => stdBasis

lemma stdBasis_apply (μ ν : Fin 1 ⊕ Fin d) : e μ ν = if μ = ν then 1 else 0 := by
  erw [stdBasis, Pi.basisFun_apply, LinearMap.stdBasis_apply']

lemma decomp_stdBasis (v : LorentzVector d) : ∑ i, v i • e i = v := by
  funext ν
  rw [Finset.sum_apply]
  rw [Finset.sum_eq_single_of_mem ν]
  · simp only [HSMul.hSMul, SMul.smul, stdBasis]
    erw [Pi.basisFun_apply]
    simp only [LinearMap.stdBasis_apply', ↓reduceIte, mul_one]
  · exact Finset.mem_univ ν
  · intros b _ hbi
    simp only [HSMul.hSMul, SMul.smul, stdBasis, mul_eq_zero]
    erw [Pi.basisFun_apply]
    simp only [Pi.single]
    apply Or.inr $ Function.update_noteq (id (Ne.symm hbi)) 1 0

@[simp]
lemma decomp_stdBasis' (v : LorentzVector d) :
    v (Sum.inl 0) • e (Sum.inl 0) + ∑ a₂ : Fin d, v (Sum.inr a₂) • e (Sum.inr a₂) = v := by
  trans ∑ i, v i • e i
  · simp only [Fin.isValue, Fintype.sum_sum_type, Finset.univ_unique, Fin.default_eq_zero,
      Finset.sum_singleton]
  · exact decomp_stdBasis v

/-- The standard unit time vector. -/
noncomputable abbrev timeVec : (LorentzVector d) := e (Sum.inl 0)

lemma timeVec_space : (@timeVec d).space = 0 := by
  funext i
  simp only [space, Function.comp_apply, stdBasis_apply, Fin.isValue, ↓reduceIte, PiLp.zero_apply]

lemma timeVec_time: (@timeVec d).time = 1 := by
  simp only [time, Fin.isValue, stdBasis_apply, ↓reduceIte]

/-!

# Reflection of space

-/

/-- The reflection of space as a linear map. -/
@[simps!]
def spaceReflectionLin : LorentzVector d →ₗ[ℝ] LorentzVector d where
  toFun x := Sum.elim (x ∘ Sum.inl) (- x ∘ Sum.inr)
  map_add' x y := by
    funext i
    rcases i with i | i
    · rfl
    · simp only [Sum.elim_inr, Pi.neg_apply]
      apply neg_add
  map_smul' c x := by
    funext i
    rcases i with i | i
    · rfl
    · simp [HSMul.hSMul, SMul.smul]

/-- The reflection of space. -/
@[simp]
def spaceReflection : LorentzVector d := spaceReflectionLin v

lemma spaceReflection_space : v.spaceReflection.space = - v.space := rfl

lemma spaceReflection_time : v.spaceReflection.time = v.time


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2

:= by
  rw [time_sq_eq_metric_add_space, v.2]


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

:= by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time|

:= by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time|

:=
  le_of_lt (norm_space_le_abs_time v)


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1

:= by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time

:= by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time

:= by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖

:= by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time

:= by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0

:= by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d

:= by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d := by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d := by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg

lemma time_nonneg : 0 ≤ f.1.1.time := le_of_lt f.2

lemma abs_time : |f.1.1.time| = f.1.1.time


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d := by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg

lemma time_nonneg : 0 ≤ f.1.1.time := le_of_lt f.2

lemma abs_time : |f.1.1.time| = f.1.1.time := abs_of_nonneg (time_nonneg f)

lemma time_eq_sqrt : f.1.1.time = (1 + ‖f.1.1.space‖ ^ 2).sqrt

:= by
  symm
  rw [Real.sqrt_eq_cases]
  apply Or.inl
  rw [← time_sq, sq]
  exact ⟨rfl, time_nonneg f⟩


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d := by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg

lemma time_nonneg : 0 ≤ f.1.1.time := le_of_lt f.2

lemma abs_time : |f.1.1.time| = f.1.1.time := abs_of_nonneg (time_nonneg f)

lemma time_eq_sqrt : f.1.1.time = (1 + ‖f.1.1.space‖ ^ 2).sqrt := by
  symm
  rw [Real.sqrt_eq_cases]
  apply Or.inl
  rw [← time_sq, sq]
  exact ⟨rfl, time_nonneg f⟩

/-!

# The sign of ⟪v, w.1⟫ₘ different v and w

-/

:= by
  apply le_trans (time_abs_sub_space_norm f f'.1)
  rw [abs_time f, abs_time f']
  exact ge_sub_norm f.1.1 f'.1.1


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d := by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg

lemma time_nonneg : 0 ≤ f.1.1.time := le_of_lt f.2

lemma abs_time : |f.1.1.time| = f.1.1.time := abs_of_nonneg (time_nonneg f)

lemma time_eq_sqrt : f.1.1.time = (1 + ‖f.1.1.space‖ ^ 2).sqrt := by
  symm
  rw [Real.sqrt_eq_cases]
  apply Or.inl
  rw [← time_sq, sq]
  exact ⟨rfl, time_nonneg f⟩

/-!

# The sign of ⟪v, w.1⟫ₘ different v and w

-/

lemma metric_nonneg : 0 ≤ ⟪f, f'.1.1⟫ₘ := by
  apply le_trans (time_abs_sub_space_norm f f'.1)
  rw [abs_time f, abs_time f']
  exact ge_sub_norm f.1.1 f'.1.1

lemma one_add_metric_non_zero : 1 + ⟪f, f'.1.1⟫ₘ ≠ 0


/-
Copyright (c) 2024 Joseph Tooby-Smith. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzVector.Basic
import HepLean.SpaceTime.MinkowskiMetric
/-!

# Lorentz vectors with norm one

-/

open minkowskiMetric

/-- The set of Lorentz vectors with norm 1. -/
@[simp]
def NormOneLorentzVector (d : ℕ) : Set (LorentzVector d) :=
  fun x => ⟪x, x⟫ₘ = 1

instance : TopologicalSpace (NormOneLorentzVector d) := instTopologicalSpaceSubtype

namespace NormOneLorentzVector

variable {d : ℕ}

section
variable (v w : NormOneLorentzVector d)

lemma mem_iff {x : LorentzVector d} : x ∈ NormOneLorentzVector d ↔ ⟪x, x⟫ₘ = 1 := by
  rfl

/-- The negative of a `NormOneLorentzVector` as a `NormOneLorentzVector`. -/
def neg : NormOneLorentzVector d := ⟨- v, by
  rw [mem_iff]
  simp only [map_neg, LinearMap.neg_apply, neg_neg]
  exact v.2⟩

lemma time_sq : v.1.time ^ 2 = 1 + ‖v.1.space‖ ^ 2 := by
  rw [time_sq_eq_metric_add_space, v.2]

lemma abs_time_ge_one : 1 ≤ |v.1.time| := by
  have h1 := leq_time_sq v.1
  rw [v.2] at h1
  exact (one_le_sq_iff_one_le_abs _).mp h1

lemma norm_space_le_abs_time : ‖v.1.space‖ < |v.1.time| := by
  rw [(abs_norm _).symm, ← @sq_lt_sq, time_sq]
  exact lt_one_add (‖(v.1).space‖ ^ 2)

lemma norm_space_leq_abs_time : ‖v.1.space‖ ≤ |v.1.time| :=
  le_of_lt (norm_space_le_abs_time v)

lemma time_le_minus_one_or_ge_one : v.1.time ≤ -1 ∨ 1 ≤ v.1.time :=
  le_abs'.mp (abs_time_ge_one v)

lemma time_nonpos_iff : v.1.time ≤ 0 ↔ v.1.time ≤ - 1 := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · exact h1
    · linarith
  · intro h
    linarith

lemma time_nonneg_iff : 0 ≤ v.1.time ↔ 1 ≤ v.1.time := by
  apply Iff.intro
  · intro h
    cases' time_le_minus_one_or_ge_one v with h1 h1
    · linarith
    · exact h1
  · intro h
    linarith

lemma time_pos_iff : 0 < v.1.time ↔ 1 ≤ v.1.time := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact (time_nonneg_iff v).mp (le_of_lt h)
  · linarith

lemma time_abs_sub_space_norm :
    0 ≤ |v.1.time| * |w.1.time| - ‖v.1.space‖ * ‖w.1.space‖ := by
  apply sub_nonneg.mpr
  apply mul_le_mul (norm_space_leq_abs_time v) (norm_space_leq_abs_time w) ?_ ?_
  · exact norm_nonneg w.1.space
  · exact abs_nonneg (v.1 _)

/-!

# Future pointing norm one Lorentz vectors

-/

/-- The future pointing Lorentz vectors with Norm one. -/
def FuturePointing (d : ℕ) : Set (NormOneLorentzVector d) :=
  fun x => 0 < x.1.time

instance : TopologicalSpace (FuturePointing d) := instTopologicalSpaceSubtype

namespace FuturePointing

section
variable (f f' : FuturePointing d)

lemma mem_iff : v ∈ FuturePointing d ↔ 0 < v.1.time := by
  rfl

lemma mem_iff_time_nonneg : v ∈ FuturePointing d ↔ 0 ≤ v.1.time := by
  refine Iff.intro (fun h => le_of_lt h) (fun h => ?_)
  rw [time_nonneg_iff] at h
  rw [mem_iff]
  linarith

lemma not_mem_iff : v ∉ FuturePointing d ↔ v.1.time ≤ 0 := by
  refine Iff.intro (fun h => ?_) (fun h => ?_)
  · exact le_of_not_lt ((mem_iff v).mp.mt h)
  · have h1 := (mem_iff v).mp.mt
    simp only [LorentzVector.time, Fin.isValue, not_lt] at h1
    exact h1 h

lemma not_mem_iff_neg : v ∉ FuturePointing d ↔ neg v ∈ FuturePointing d := by
  rw [not_mem_iff, mem_iff_time_nonneg]
  simp only [Fin.isValue, neg]
  change _ ↔ 0 ≤ - v.1 _
  exact Iff.symm neg_nonneg

lemma time_nonneg : 0 ≤ f.1.1.time := le_of_lt f.2

lemma abs_time : |f.1.1.time| = f.1.1.time := abs_of_nonneg (time_nonneg f)

lemma time_eq_sqrt : f.1.1.time = (1 + ‖f.1.1.space‖ ^ 2).sqrt := by
  symm
  rw [Real.sqrt_eq_cases]
  apply Or.inl
  rw [← time_sq, sq]
  exact ⟨rfl, time_nonneg f⟩

/-!

# The sign of ⟪v, w.1⟫ₘ different v and w

-/

lemma metric_nonneg : 0 ≤ ⟪f, f'.1.1⟫ₘ := by
  apply le_trans (time_abs_sub_space_norm f f'.1)
  rw [abs_time f, abs_time f']
  exact ge_sub_norm f.1.1 f'.1.1

lemma one_add_metric_non_zero : 1 + ⟪f, f'.1.1⟫ₘ ≠ 0 := by
  linarith [metric_nonneg f f']

/-!

# The sign of ⟪v, w.1.spaceReflection⟫ₘ different v and w

-/

section
variable {v w : NormOneLorentzVector d}

lemma metric_reflect_mem_mem (h : v ∈ FuturePointing d) (hw : w ∈ FuturePointing d) :
    0 ≤ ⟪v.1, w.1.spaceReflection⟫ₘ

:= by
  apply le_trans (time_abs_sub_space_norm v w)
  rw [abs_time ⟨v, h⟩, abs_time ⟨w, hw⟩, sub_eq_add_neg, right_spaceReflection]
  apply (add_le_add_iff_left _).mpr
  rw [neg_le]
  apply le_trans (neg_le_abs _ : _ ≤ |⟪(v.1).space, (w.1).space⟫_ℝ|) ?_
  exact abs_real_inner_le_norm (v.1).space (w.1).space