refactor: Index notation

This commit is contained in:
jstoobysmith 2024-08-23 11:14:48 -04:00
parent 097571453f
commit cf0cbb78bb
8 changed files with 551 additions and 438 deletions

View file

@ -12,16 +12,9 @@ import HepLean.SpaceTime.LorentzTensor.Contraction
# Index lists and color
In this file we look at the interaction of index lists with color.
The main definiton of this file is `ColorIndexList`. This type defines the
permissible index lists which can be used for a tensor. These are lists of indices for which
every index with a dual has a unique dual, and the color of that dual (when it exists) is dual
to the color of the index.
We also define `AppendCond`, which is a condition on two `ColorIndexList`s which allows them to be
appended to form a new `ColorIndexList`.
In this file we look at the interaction of index lists and color.
The main definition of this file is `ColorCond`.
-/
namespace IndexNotation
@ -593,430 +586,4 @@ end ColorCond
end IndexList
variable (𝓒 : TensorColor)
variable [IndexNotation 𝓒.Color] [Fintype 𝓒.Color] [DecidableEq 𝓒.Color]
/-- A list of indices with the additional constraint that if a index has a dual,
that dual is unique, and the dual of an index has dual color to that index.
This is the permissible type of indices which can be used for a tensor. For example,
the index list `['ᵘ¹', 'ᵤ₁']` can be extended to a `ColorIndexList` but the index list
`['ᵘ¹', 'ᵤ₁', 'ᵤ₁']` cannot. -/
structure ColorIndexList (𝓒 : TensorColor) [IndexNotation 𝓒.Color] extends IndexList 𝓒.Color where
/-- The condition that for index with a dual, that dual is the unique other index with
an identical `id`. -/
unique_duals : toIndexList.withDual = toIndexList.withUniqueDual
/-- The condition that for an index with a dual, that dual has dual color to the index. -/
dual_color : IndexList.ColorCond toIndexList
namespace ColorIndexList
variable {𝓒 : TensorColor} [IndexNotation 𝓒.Color] [Fintype 𝓒.Color] [DecidableEq 𝓒.Color]
variable (l l2 : ColorIndexList 𝓒)
open IndexList TensorColor
instance : Coe (ColorIndexList 𝓒) (IndexList 𝓒.Color) := ⟨fun l => l.toIndexList⟩
/-- The colorMap of a `ColorIndexList` as a `𝓒.ColorMap`.
This is to be compared with `colorMap` which is a map `Fin l.length → 𝓒.Color`. -/
def colorMap' : 𝓒.ColorMap (Fin l.length) :=
l.colorMap
@[ext]
lemma ext {l l' : ColorIndexList 𝓒} (h : l.val = l'.val) : l = l' := by
cases l
cases l'
simp_all
apply IndexList.ext
exact h
lemma ext' {l l' : ColorIndexList 𝓒} (h : l.toIndexList = l'.toIndexList) : l = l' := by
cases l
cases l'
simp_all
/-! TODO: `orderEmbOfFin_univ` should be replaced with a mathlib lemma if possible. -/
lemma orderEmbOfFin_univ (n m : ) (h : n = m) :
Finset.orderEmbOfFin (Finset.univ : Finset (Fin n)) (by simp [h]: Finset.univ.card = m) =
(Fin.castOrderIso h.symm).toOrderEmbedding := by
symm
have h1 : (Fin.castOrderIso h.symm).toFun =
(Finset.orderEmbOfFin (Finset.univ : Finset (Fin n))
(by simp [h]: Finset.univ.card = m)).toFun := by
apply Finset.orderEmbOfFin_unique
intro x
exact Finset.mem_univ ((Fin.castOrderIso (Eq.symm h)).toFun x)
exact fun ⦃a b⦄ a => a
exact Eq.symm (Fin.orderEmbedding_eq (congrArg Set.range (id (Eq.symm h1))))
/-!
## Cons for `ColorIndexList`
-/
/-- The `ColorIndexList` whose underlying list of indices is empty. -/
def empty : ColorIndexList 𝓒 where
val := []
unique_duals := rfl
dual_color := rfl
/-- The `ColorIndexList` obtained by adding an index, subject to some conditions,
to the start of `l`. -/
def cons (I : Index 𝓒.Color) (hI1 : l.val.countP (fun J => I.id = J.id) ≤ 1)
(hI2 : l.val.countP (fun J => I.id = J.id) =
l.val.countP (fun J => I.id = J.id ∧ I.toColor = 𝓒.τ J.toColor)) : ColorIndexList 𝓒 where
toIndexList := l.toIndexList.cons I
unique_duals := by
symm
rw [withUniqueDual_eq_withDual_cons_iff]
· exact hI1
· exact l.unique_duals.symm
dual_color := by
have h1 : (l.toIndexList.cons I).withUniqueDual = (l.toIndexList.cons I).withDual ∧
(l.toIndexList.cons I).ColorCond := by
rw [ColorCond.cons_iff]
exact ⟨l.unique_duals.symm, l.dual_color, hI1, hI2⟩
exact h1.2
/-- The tail of a `ColorIndexList`. In other words, the `ColorIndexList` with the first index
removed. -/
def tail (l : ColorIndexList 𝓒) : ColorIndexList 𝓒 where
toIndexList := l.toIndexList.tail
unique_duals := by
by_cases hl : l.toIndexList = {val := []}
· rw [hl]
simp [IndexList.tail]
rfl
· have hl' := l.head_cons_tail hl
have h1 := l.unique_duals
rw [hl'] at h1
exact (withUniqueDual_eq_withDual_of_cons _ h1.symm).symm
dual_color := by
by_cases hl : l.toIndexList = {val := []}
· rw [hl]
simp [IndexList.tail]
rfl
· have hl' := l.head_cons_tail hl
have h1 := l.unique_duals
have h2 := l.dual_color
rw [hl'] at h1 h2
exact (ColorCond.of_cons _ h2 h1.symm)
@[simp]
lemma tail_toIndexList : l.tail.toIndexList = l.toIndexList.tail := by
rfl
/-- The first index in a `ColorIndexList`. -/
def head (h : l ≠ empty) : Index 𝓒.Color :=
l.toIndexList.head (by
cases' l
simpa [empty] using h)
lemma head_uniqueDual (h : l ≠ empty) :
l.tail.val.countP (fun J => (l.head h).id = J.id) ≤ 1 := by
have h1 := l.unique_duals.symm
have hl : l.toIndexList = (l.tail.toIndexList.cons (l.head h)) := by
simpa using l.head_cons_tail _
rw [hl] at h1
rw [withUniqueDual_eq_withDual_cons_iff'] at h1
exact h1.2
lemma head_color_dual (h : l ≠ empty) :
l.tail.val.countP (fun J => (l.head h).id = J.id) =
l.tail.val.countP (fun J => (l.head h).id = J.id ∧ (l.head h).toColor = 𝓒.τ J.toColor) := by
have h1 : l.withUniqueDual = l.withDual ∧ ColorCond l := ⟨l.unique_duals.symm, l.dual_color⟩
have hl : l.toIndexList = (l.tail.toIndexList.cons (l.head h)) := by
simpa using l.head_cons_tail _
rw [hl, ColorCond.cons_iff] at h1
exact h1.2.2.2
lemma head_cons_tail (h : l ≠ empty) :
l = (l.tail).cons (l.head h) (l.head_uniqueDual h) (l.head_color_dual h) := by
apply ext'
exact IndexList.head_cons_tail _ _
/-!
## Induction for `ColorIndexList`
-/
lemma induction {P : ColorIndexList 𝓒 → Prop } (h_nil : P empty)
(h_cons : ∀ (I : Index 𝓒.Color) (l : ColorIndexList 𝓒)
(hI1 : l.val.countP (fun J => I.id = J.id) ≤ 1) (hI2 : l.val.countP (fun J => I.id = J.id) =
l.val.countP (fun J => I.id = J.id ∧ I.toColor = 𝓒.τ J.toColor)), P l → P (l.cons I hI1 hI2))
(l : ColorIndexList 𝓒) : P l := by
by_cases h : l = empty
· subst l
exact h_nil
· rw [l.head_cons_tail h]
refine h_cons (l.head h) (l.tail) (l.head_uniqueDual h) (l.head_color_dual h) ?_
exact induction h_nil h_cons l.tail
termination_by l.length
decreasing_by {
by_cases hn : l = empty
· subst hn
simp
exact False.elim (h rfl)
· have h1 : l.tail.length < l.length := by
simp [IndexList.tail, length]
by_contra hn'
simp at hn'
have hv : l = empty := ext hn'
exact False.elim (hn hv)
exact h1
}
/-!
## Contracting an `ColorIndexList`
-/
/-- The contraction of a `ColorIndexList`, `l`.
That is, the `ColorIndexList` obtained by taking only those indices in `l` which do not
have a dual. This can be thought of as contracting all of those indices with a dual. -/
def contr : ColorIndexList 𝓒 where
toIndexList := l.toIndexList.contrIndexList
unique_duals := by
simp
dual_color := by
funext i
simp [Option.guard]
@[simp]
lemma contr_contr : l.contr.contr = l.contr := by
apply ext
simp [contr]
@[simp]
lemma contr_contr_idMap (i : Fin l.contr.contr.length) :
l.contr.contr.idMap i = l.contr.idMap (Fin.cast (by simp) i) := by
simp only [contr, contrIndexList_idMap, Fin.cast_trans]
apply congrArg
simp only [withoutDualEquiv, RelIso.coe_fn_toEquiv, Finset.coe_orderIsoOfFin_apply,
EmbeddingLike.apply_eq_iff_eq]
have h1 : l.contrIndexList.withoutDual = Finset.univ := by
have hx := l.contrIndexList.withDual_union_withoutDual
have hx2 := l.contrIndexList_withDual
simp_all
simp only [h1]
rw [orderEmbOfFin_univ]
· rfl
· rw [h1]
simp
@[simp]
lemma contr_contr_colorMap (i : Fin l.contr.contr.length) :
l.contr.contr.colorMap i = l.contr.colorMap (Fin.cast (by simp) i) := by
simp only [contr, contrIndexList_colorMap, Fin.cast_trans]
apply congrArg
simp only [withoutDualEquiv, RelIso.coe_fn_toEquiv, Finset.coe_orderIsoOfFin_apply,
EmbeddingLike.apply_eq_iff_eq]
have h1 : l.contrIndexList.withoutDual = Finset.univ := by
have hx := l.contrIndexList.withDual_union_withoutDual
have hx2 := l.contrIndexList_withDual
simp_all
simp only [h1]
rw [orderEmbOfFin_univ]
· rfl
· rw [h1]
simp
@[simp]
lemma contr_of_withDual_empty (h : l.withDual = ∅) :
l.contr = l := by
simp [contr]
apply ext
simp [l.contrIndexList_of_withDual_empty h]
@[simp]
lemma contr_getDual?_eq_none (i : Fin l.contr.length) :
l.contr.getDual? i = none := by
simp only [contr, contrIndexList_getDual?]
@[simp]
lemma contr_areDualInSelf (i j : Fin l.contr.length) :
l.contr.AreDualInSelf i j ↔ False := by
simp [contr]
/-!
## Contract equiv
-/
/-- An equivalence splitting the indices of `l` into
a sum type of those indices and their duals (with choice determined by the ordering on `Fin`),
and those indices without duals.
This equivalence is used to contract the indices of tensors. -/
def contrEquiv : (l.withUniqueDualLT ⊕ l.withUniqueDualLT) ⊕ Fin l.contr.length ≃ Fin l.length :=
(Equiv.sumCongr (l.withUniqueLTGTEquiv) (Equiv.refl _)).trans <|
(Equiv.sumCongr (Equiv.subtypeEquivRight (by
simp only [l.unique_duals, implies_true]))
(Fin.castOrderIso l.contrIndexList_length).toEquiv).trans <|
l.dualEquiv
lemma contrEquiv_inl_inl_isSome (i : l.withUniqueDualLT) :
(l.getDual? (l.contrEquiv (Sum.inl (Sum.inl i)))).isSome := by
change (l.getDual? i).isSome
have h1 : i.1 ∈ l.withUniqueDual := by
have hi2 := i.2
simp only [withUniqueDualLT, Finset.mem_filter] at hi2
exact hi2.1
exact mem_withUniqueDual_isSome l.toIndexList (↑i) h1
@[simp]
lemma contrEquiv_inl_inr_eq (i : l.withUniqueDualLT) :
(l.contrEquiv (Sum.inl (Sum.inr i))) =
(l.getDual? i.1).get (l.contrEquiv_inl_inl_isSome i) := by
rfl
@[simp]
lemma contrEquiv_inl_inl_eq (i : l.withUniqueDualLT) :
(l.contrEquiv (Sum.inl (Sum.inl i))) = i := by
rfl
lemma contrEquiv_colorMapIso :
ColorMap.MapIso (Equiv.refl (Fin l.contr.length))
(ColorMap.contr l.contrEquiv l.colorMap) l.contr.colorMap := by
simp [ColorMap.MapIso, ColorMap.contr]
funext i
simp [contr]
rfl
lemma contrEquiv_contrCond : ColorMap.ContrCond l.contrEquiv l.colorMap := by
simp only [ColorMap.ContrCond]
funext i
simp only [Function.comp_apply, contrEquiv_inl_inl_eq, contrEquiv_inl_inr_eq]
have h1 := l.dual_color
rw [ColorCond.iff_on_isSome] at h1
exact (h1 i.1 _).symm
@[simp]
lemma contrEquiv_on_withDual_empty (i : Fin l.contr.length) (h : l.withDual = ∅) :
l.contrEquiv (Sum.inr i) = Fin.cast (by simp [h]) i := by
simp [contrEquiv]
change l.dualEquiv (Sum.inr ((Fin.castOrderIso _).toEquiv i)) = _
simp [dualEquiv, withoutDualEquiv]
have h : l.withoutDual = Finset.univ := by
have hx := l.withDual_union_withoutDual
simp_all
simp [h]
rw [orderEmbOfFin_univ]
· rfl
· rw [h]
simp
/-!
## Append
-/
/-- The condition on the `ColorIndexList`s `l` and `l2` so that on appending they form
a `ColorIndexList`.
Note: `AppendCond` does not form an equivalence relation as it is not reflexive or
transitive. -/
def AppendCond : Prop :=
(l.toIndexList ++ l2.toIndexList).withUniqueDual = (l.toIndexList ++ l2.toIndexList).withDual
∧ ColorCond (l.toIndexList ++ l2.toIndexList)
/-- Given two `ColorIndexList`s satisfying `AppendCond`. The correponding combined
`ColorIndexList`. -/
def append (h : AppendCond l l2) : ColorIndexList 𝓒 where
toIndexList := l.toIndexList ++ l2.toIndexList
unique_duals := h.1.symm
dual_color := h.2
/-- The join of two `ColorIndexList` satisfying the condition `AppendCond` that they
can be appended to form a `ColorIndexList`. -/
scoped[IndexNotation.ColorIndexList] notation l " ++["h"] " l2 => append l l2 h
@[simp]
lemma append_toIndexList (h : AppendCond l l2) :
(l ++[h] l2).toIndexList = l.toIndexList ++ l2.toIndexList := by
rfl
namespace AppendCond
variable {l l2 l3 : ColorIndexList 𝓒}
@[symm]
lemma symm (h : AppendCond l l2) : AppendCond l2 l := by
apply And.intro _ (h.2.symm h.1)
rw [append_withDual_eq_withUniqueDual_symm]
exact h.1
lemma inr (h : AppendCond l l2) (h' : AppendCond (l ++[h] l2) l3) :
AppendCond l2 l3 := by
apply And.intro
· have h1 := h'.1
simp at h1
rw [append_assoc] at h1
exact l.append_withDual_eq_withUniqueDual_inr (l2.toIndexList ++ l3.toIndexList) h1
· have h1 := h'.2
simp at h1
rw [append_assoc] at h1
refine ColorCond.inr ?_ h1
rw [← append_assoc]
exact h'.1
lemma assoc (h : AppendCond l l2) (h' : AppendCond (l ++[h] l2) l3) :
AppendCond l (l2 ++[h.inr h'] l3) := by
apply And.intro
· simp
rw [← append_assoc]
simpa using h'.1
· simp
rw [← append_assoc]
exact h'.2
lemma swap (h : AppendCond l l2) (h' : AppendCond (l ++[h] l2) l3) :
AppendCond (l2 ++[h.symm] l) l3:= by
apply And.intro
· simp only [append_toIndexList]
rw [← append_withDual_eq_withUniqueDual_swap]
simpa using h'.1
· exact ColorCond.swap h'.1 h'.2
/-! TODO: Show that `AppendCond l l2` implies `AppendCond l.contr l2.contr`. -/
/-! TODO: Show that `(l1.contr ++[h.contr] l2.contr).contr = (l1 ++[h] l2)` -/
lemma of_eq (h1 : l.withUniqueDual = l.withDual)
(h2 : l2.withUniqueDual = l2.withDual)
(h3 : l.withUniqueDualInOther l2 = l.withDualInOther l2)
(h4 : l2.withUniqueDualInOther l = l2.withDualInOther l)
(h5 : ColorCond.bool (l.toIndexList ++ l2.toIndexList)) :
AppendCond l l2 := by
rw [AppendCond]
rw [append_withDual_eq_withUniqueDual_iff']
simp_all
exact ColorCond.iff_bool.mpr h5
/-- A boolean which is true for two index lists `l` and `l2` if on appending
they can form a `ColorIndexList`. -/
def bool (l l2 : IndexList 𝓒.Color) : Bool :=
if ¬ (l ++ l2).withUniqueDual = (l ++ l2).withDual then
false
else
ColorCond.bool (l ++ l2)
lemma bool_iff (l l2 : IndexList 𝓒.Color) :
bool l l2 ↔ (l ++ l2).withUniqueDual = (l ++ l2).withDual ∧ ColorCond.bool (l ++ l2) := by
simp [bool]
lemma iff_bool (l l2 : ColorIndexList 𝓒) : AppendCond l l2 ↔ bool l.toIndexList l2.toIndexList := by
rw [AppendCond]
simp [bool]
rw [ColorCond.iff_bool]
simp
end AppendCond
end ColorIndexList
end IndexNotation

View file

@ -0,0 +1,133 @@
/-
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.LorentzTensor.IndexNotation.ColorIndexList.Basic
import HepLean.SpaceTime.LorentzTensor.Basic
import Init.Data.List.Lemmas
/-!
# Appending two ColorIndexLists
We define the contraction of ColorIndexLists.
-/
namespace IndexNotation
namespace ColorIndexList
variable {𝓒 : TensorColor} [IndexNotation 𝓒.Color] [Fintype 𝓒.Color] [DecidableEq 𝓒.Color]
(l l2 : ColorIndexList 𝓒)
open IndexList TensorColor
/-!
## Append
-/
/-- The condition on the `ColorIndexList`s `l` and `l2` so that on appending they form
a `ColorIndexList`.
Note: `AppendCond` does not form an equivalence relation as it is not reflexive or
transitive. -/
def AppendCond : Prop :=
(l.toIndexList ++ l2.toIndexList).withUniqueDual = (l.toIndexList ++ l2.toIndexList).withDual
∧ ColorCond (l.toIndexList ++ l2.toIndexList)
/-- Given two `ColorIndexList`s satisfying `AppendCond`. The correponding combined
`ColorIndexList`. -/
def append (h : AppendCond l l2) : ColorIndexList 𝓒 where
toIndexList := l.toIndexList ++ l2.toIndexList
unique_duals := h.1.symm
dual_color := h.2
/-- The join of two `ColorIndexList` satisfying the condition `AppendCond` that they
can be appended to form a `ColorIndexList`. -/
scoped[IndexNotation.ColorIndexList] notation l " ++["h"] " l2 => append l l2 h
@[simp]
lemma append_toIndexList (h : AppendCond l l2) :
(l ++[h] l2).toIndexList = l.toIndexList ++ l2.toIndexList := by
rfl
namespace AppendCond
variable {l l2 l3 : ColorIndexList 𝓒}
@[symm]
lemma symm (h : AppendCond l l2) : AppendCond l2 l := by
apply And.intro _ (h.2.symm h.1)
rw [append_withDual_eq_withUniqueDual_symm]
exact h.1
lemma inr (h : AppendCond l l2) (h' : AppendCond (l ++[h] l2) l3) :
AppendCond l2 l3 := by
apply And.intro
· have h1 := h'.1
simp at h1
rw [append_assoc] at h1
exact l.append_withDual_eq_withUniqueDual_inr (l2.toIndexList ++ l3.toIndexList) h1
· have h1 := h'.2
simp at h1
rw [append_assoc] at h1
refine ColorCond.inr ?_ h1
rw [← append_assoc]
exact h'.1
lemma assoc (h : AppendCond l l2) (h' : AppendCond (l ++[h] l2) l3) :
AppendCond l (l2 ++[h.inr h'] l3) := by
apply And.intro
· simp
rw [← append_assoc]
simpa using h'.1
· simp
rw [← append_assoc]
exact h'.2
lemma swap (h : AppendCond l l2) (h' : AppendCond (l ++[h] l2) l3) :
AppendCond (l2 ++[h.symm] l) l3:= by
apply And.intro
· simp only [append_toIndexList]
rw [← append_withDual_eq_withUniqueDual_swap]
simpa using h'.1
· exact ColorCond.swap h'.1 h'.2
/-! TODO: Show that `AppendCond l l2` implies `AppendCond l.contr l2.contr`. -/
/-! TODO: Show that `(l1.contr ++[h.contr] l2.contr).contr = (l1 ++[h] l2)` -/
lemma of_eq (h1 : l.withUniqueDual = l.withDual)
(h2 : l2.withUniqueDual = l2.withDual)
(h3 : l.withUniqueDualInOther l2 = l.withDualInOther l2)
(h4 : l2.withUniqueDualInOther l = l2.withDualInOther l)
(h5 : ColorCond.bool (l.toIndexList ++ l2.toIndexList)) :
AppendCond l l2 := by
rw [AppendCond]
rw [append_withDual_eq_withUniqueDual_iff']
simp_all
exact ColorCond.iff_bool.mpr h5
/-- A boolean which is true for two index lists `l` and `l2` if on appending
they can form a `ColorIndexList`. -/
def bool (l l2 : IndexList 𝓒.Color) : Bool :=
if ¬ (l ++ l2).withUniqueDual = (l ++ l2).withDual then
false
else
ColorCond.bool (l ++ l2)
lemma bool_iff (l l2 : IndexList 𝓒.Color) :
bool l l2 ↔ (l ++ l2).withUniqueDual = (l ++ l2).withDual ∧ ColorCond.bool (l ++ l2) := by
simp [bool]
lemma iff_bool (l l2 : ColorIndexList 𝓒) : AppendCond l l2 ↔ bool l.toIndexList l2.toIndexList := by
rw [AppendCond]
simp [bool]
rw [ColorCond.iff_bool]
simp
end AppendCond
end ColorIndexList
end IndexNotation

View file

@ -0,0 +1,204 @@
/-
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.LorentzTensor.IndexNotation.Color
import HepLean.SpaceTime.LorentzTensor.IndexNotation.OnlyUniqueDuals
import HepLean.SpaceTime.LorentzTensor.Basic
import Init.Data.List.Lemmas
import HepLean.SpaceTime.LorentzTensor.Contraction
/-!
# Index lists and color
The main definiton of this file is `ColorIndexList`. This type defines the
permissible index lists which can be used for a tensor. These are lists of indices for which
every index with a dual has a unique dual, and the color of that dual (when it exists) is dual
to the color of the index.
We also define `AppendCond`, which is a condition on two `ColorIndexList`s which allows them to be
appended to form a new `ColorIndexList`.
-/
namespace IndexNotation
variable (𝓒 : TensorColor)
variable [IndexNotation 𝓒.Color] [Fintype 𝓒.Color] [DecidableEq 𝓒.Color]
/-- A list of indices with the additional constraint that if a index has a dual,
that dual is unique, and the dual of an index has dual color to that index.
This is the permissible type of indices which can be used for a tensor. For example,
the index list `['ᵘ¹', 'ᵤ₁']` can be extended to a `ColorIndexList` but the index list
`['ᵘ¹', 'ᵤ₁', 'ᵤ₁']` cannot. -/
structure ColorIndexList (𝓒 : TensorColor) [IndexNotation 𝓒.Color] extends IndexList 𝓒.Color where
/-- The condition that for index with a dual, that dual is the unique other index with
an identical `id`. -/
unique_duals : toIndexList.withDual = toIndexList.withUniqueDual
/-- The condition that for an index with a dual, that dual has dual color to the index. -/
dual_color : IndexList.ColorCond toIndexList
namespace ColorIndexList
variable {𝓒 : TensorColor} [IndexNotation 𝓒.Color] [Fintype 𝓒.Color] [DecidableEq 𝓒.Color]
variable (l l2 : ColorIndexList 𝓒)
open IndexList TensorColor
instance : Coe (ColorIndexList 𝓒) (IndexList 𝓒.Color) := ⟨fun l => l.toIndexList⟩
/-- The colorMap of a `ColorIndexList` as a `𝓒.ColorMap`.
This is to be compared with `colorMap` which is a map `Fin l.length → 𝓒.Color`. -/
def colorMap' : 𝓒.ColorMap (Fin l.length) :=
l.colorMap
@[ext]
lemma ext {l l' : ColorIndexList 𝓒} (h : l.val = l'.val) : l = l' := by
cases l
cases l'
simp_all
apply IndexList.ext
exact h
lemma ext' {l l' : ColorIndexList 𝓒} (h : l.toIndexList = l'.toIndexList) : l = l' := by
cases l
cases l'
simp_all
/-! TODO: `orderEmbOfFin_univ` should be replaced with a mathlib lemma if possible. -/
lemma orderEmbOfFin_univ (n m : ) (h : n = m) :
Finset.orderEmbOfFin (Finset.univ : Finset (Fin n)) (by simp [h]: Finset.univ.card = m) =
(Fin.castOrderIso h.symm).toOrderEmbedding := by
symm
have h1 : (Fin.castOrderIso h.symm).toFun =
(Finset.orderEmbOfFin (Finset.univ : Finset (Fin n))
(by simp [h]: Finset.univ.card = m)).toFun := by
apply Finset.orderEmbOfFin_unique
intro x
exact Finset.mem_univ ((Fin.castOrderIso (Eq.symm h)).toFun x)
exact fun ⦃a b⦄ a => a
exact Eq.symm (Fin.orderEmbedding_eq (congrArg Set.range (id (Eq.symm h1))))
/-!
## Cons for `ColorIndexList`
-/
/-- The `ColorIndexList` whose underlying list of indices is empty. -/
def empty : ColorIndexList 𝓒 where
val := []
unique_duals := rfl
dual_color := rfl
/-- The `ColorIndexList` obtained by adding an index, subject to some conditions,
to the start of `l`. -/
def cons (I : Index 𝓒.Color) (hI1 : l.val.countP (fun J => I.id = J.id) ≤ 1)
(hI2 : l.val.countP (fun J => I.id = J.id) =
l.val.countP (fun J => I.id = J.id ∧ I.toColor = 𝓒.τ J.toColor)) : ColorIndexList 𝓒 where
toIndexList := l.toIndexList.cons I
unique_duals := by
symm
rw [withUniqueDual_eq_withDual_cons_iff]
· exact hI1
· exact l.unique_duals.symm
dual_color := by
have h1 : (l.toIndexList.cons I).withUniqueDual = (l.toIndexList.cons I).withDual ∧
(l.toIndexList.cons I).ColorCond := by
rw [ColorCond.cons_iff]
exact ⟨l.unique_duals.symm, l.dual_color, hI1, hI2⟩
exact h1.2
/-- The tail of a `ColorIndexList`. In other words, the `ColorIndexList` with the first index
removed. -/
def tail (l : ColorIndexList 𝓒) : ColorIndexList 𝓒 where
toIndexList := l.toIndexList.tail
unique_duals := by
by_cases hl : l.toIndexList = {val := []}
· rw [hl]
simp [IndexList.tail]
rfl
· have hl' := l.head_cons_tail hl
have h1 := l.unique_duals
rw [hl'] at h1
exact (withUniqueDual_eq_withDual_of_cons _ h1.symm).symm
dual_color := by
by_cases hl : l.toIndexList = {val := []}
· rw [hl]
simp [IndexList.tail]
rfl
· have hl' := l.head_cons_tail hl
have h1 := l.unique_duals
have h2 := l.dual_color
rw [hl'] at h1 h2
exact (ColorCond.of_cons _ h2 h1.symm)
@[simp]
lemma tail_toIndexList : l.tail.toIndexList = l.toIndexList.tail := by
rfl
/-- The first index in a `ColorIndexList`. -/
def head (h : l ≠ empty) : Index 𝓒.Color :=
l.toIndexList.head (by
cases' l
simpa [empty] using h)
lemma head_uniqueDual (h : l ≠ empty) :
l.tail.val.countP (fun J => (l.head h).id = J.id) ≤ 1 := by
have h1 := l.unique_duals.symm
have hl : l.toIndexList = (l.tail.toIndexList.cons (l.head h)) := by
simpa using l.head_cons_tail _
rw [hl] at h1
rw [withUniqueDual_eq_withDual_cons_iff'] at h1
exact h1.2
lemma head_color_dual (h : l ≠ empty) :
l.tail.val.countP (fun J => (l.head h).id = J.id) =
l.tail.val.countP (fun J => (l.head h).id = J.id ∧ (l.head h).toColor = 𝓒.τ J.toColor) := by
have h1 : l.withUniqueDual = l.withDual ∧ ColorCond l := ⟨l.unique_duals.symm, l.dual_color⟩
have hl : l.toIndexList = (l.tail.toIndexList.cons (l.head h)) := by
simpa using l.head_cons_tail _
rw [hl, ColorCond.cons_iff] at h1
exact h1.2.2.2
lemma head_cons_tail (h : l ≠ empty) :
l = (l.tail).cons (l.head h) (l.head_uniqueDual h) (l.head_color_dual h) := by
apply ext'
exact IndexList.head_cons_tail _ _
/-!
## Induction for `ColorIndexList`
-/
lemma induction {P : ColorIndexList 𝓒 → Prop } (h_nil : P empty)
(h_cons : ∀ (I : Index 𝓒.Color) (l : ColorIndexList 𝓒)
(hI1 : l.val.countP (fun J => I.id = J.id) ≤ 1) (hI2 : l.val.countP (fun J => I.id = J.id) =
l.val.countP (fun J => I.id = J.id ∧ I.toColor = 𝓒.τ J.toColor)), P l → P (l.cons I hI1 hI2))
(l : ColorIndexList 𝓒) : P l := by
by_cases h : l = empty
· subst l
exact h_nil
· rw [l.head_cons_tail h]
refine h_cons (l.head h) (l.tail) (l.head_uniqueDual h) (l.head_color_dual h) ?_
exact induction h_nil h_cons l.tail
termination_by l.length
decreasing_by {
by_cases hn : l = empty
· subst hn
simp
exact False.elim (h rfl)
· have h1 : l.tail.length < l.length := by
simp [IndexList.tail, length]
by_contra hn'
simp at hn'
have hv : l = empty := ext hn'
exact False.elim (hn hv)
exact h1
}
end ColorIndexList
end IndexNotation

View file

@ -0,0 +1,199 @@
/-
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.LorentzTensor.IndexNotation.ColorIndexList.Basic
import HepLean.SpaceTime.LorentzTensor.Basic
import Init.Data.List.Lemmas
/-!
# Contraction of ColorIndexLists
We define the contraction of ColorIndexLists.
-/
namespace IndexNotation
namespace ColorIndexList
variable {𝓒 : TensorColor} [IndexNotation 𝓒.Color] [Fintype 𝓒.Color] [DecidableEq 𝓒.Color]
(l l2 : ColorIndexList 𝓒)
open IndexList TensorColor
/-!
## Contracting an `ColorIndexList`
-/
/-- The contraction of a `ColorIndexList`, `l`.
That is, the `ColorIndexList` obtained by taking only those indices in `l` which do not
have a dual. This can be thought of as contracting all of those indices with a dual. -/
def contr : ColorIndexList 𝓒 where
toIndexList := l.toIndexList.contrIndexList
unique_duals := by
simp
dual_color := by
funext i
simp [Option.guard]
@[simp]
lemma contr_contr : l.contr.contr = l.contr := by
apply ext
simp [contr]
@[simp]
lemma contr_contr_idMap (i : Fin l.contr.contr.length) :
l.contr.contr.idMap i = l.contr.idMap (Fin.cast (by simp) i) := by
simp only [contr, contrIndexList_idMap, Fin.cast_trans]
apply congrArg
simp only [withoutDualEquiv, RelIso.coe_fn_toEquiv, Finset.coe_orderIsoOfFin_apply,
EmbeddingLike.apply_eq_iff_eq]
have h1 : l.contrIndexList.withoutDual = Finset.univ := by
have hx := l.contrIndexList.withDual_union_withoutDual
have hx2 := l.contrIndexList_withDual
simp_all
simp only [h1]
rw [orderEmbOfFin_univ]
· rfl
· rw [h1]
simp
@[simp]
lemma contr_contr_colorMap (i : Fin l.contr.contr.length) :
l.contr.contr.colorMap i = l.contr.colorMap (Fin.cast (by simp) i) := by
simp only [contr, contrIndexList_colorMap, Fin.cast_trans]
apply congrArg
simp only [withoutDualEquiv, RelIso.coe_fn_toEquiv, Finset.coe_orderIsoOfFin_apply,
EmbeddingLike.apply_eq_iff_eq]
have h1 : l.contrIndexList.withoutDual = Finset.univ := by
have hx := l.contrIndexList.withDual_union_withoutDual
have hx2 := l.contrIndexList_withDual
simp_all
simp only [h1]
rw [orderEmbOfFin_univ]
· rfl
· rw [h1]
simp
@[simp]
lemma contr_of_withDual_empty (h : l.withDual = ∅) :
l.contr = l := by
simp [contr]
apply ext
simp [l.contrIndexList_of_withDual_empty h]
@[simp]
lemma contr_getDual?_eq_none (i : Fin l.contr.length) :
l.contr.getDual? i = none := by
simp only [contr, contrIndexList_getDual?]
@[simp]
lemma contr_areDualInSelf (i j : Fin l.contr.length) :
l.contr.AreDualInSelf i j ↔ False := by
simp [contr]
lemma contr_countP_eq_zero_of_countP (I : Index 𝓒.Color)
(h : l.val.countP (fun J => I.id = J.id) = 0) :
l.contr.val.countP (fun J => I.id = J.id) = 0 := by
simp [contr]
exact countP_contrIndexList_zero_of_countP l.toIndexList I h
lemma contr_countP (I : Index 𝓒.Color) :
l.contr.val.countP (fun J => I.id = J.id) =
(l.val.filter (fun J => I.id = J.id)).countP (fun i => l.val.countP (fun j => i.id = j.id) = 1) := by
simp [contr, contrIndexList]
rw [List.countP_filter, List.countP_filter]
congr
funext J
simp
exact
Bool.and_comm (decide (I.id = J.id))
(decide (List.countP (fun j => decide (J.id = j.id)) l.val = 1))
lemma contr_cons_dual (I : Index 𝓒.Color) (hI1 : l.val.countP (fun J => I.id = J.id) ≤ 1) :
l.contr.val.countP (fun J => I.id = J.id) ≤ 1 := by
rw [contr_countP]
by_cases hI1 : l.val.countP (fun J => I.id = J.id) = 0
· rw [filter_of_countP_zero]
· simp
· exact hI1
· have hI1 : l.val.countP (fun J => I.id = J.id) = 1 := by
omega
rw [consDual_filter]
· simp_all
· exact hI1
/-!
## Contract equiv
-/
/-- An equivalence splitting the indices of `l` into
a sum type of those indices and their duals (with choice determined by the ordering on `Fin`),
and those indices without duals.
This equivalence is used to contract the indices of tensors. -/
def contrEquiv : (l.withUniqueDualLT ⊕ l.withUniqueDualLT) ⊕ Fin l.contr.length ≃ Fin l.length :=
(Equiv.sumCongr (l.withUniqueLTGTEquiv) (Equiv.refl _)).trans <|
(Equiv.sumCongr (Equiv.subtypeEquivRight (by
simp only [l.unique_duals, implies_true]))
(Fin.castOrderIso l.contrIndexList_length).toEquiv).trans <|
l.dualEquiv
lemma contrEquiv_inl_inl_isSome (i : l.withUniqueDualLT) :
(l.getDual? (l.contrEquiv (Sum.inl (Sum.inl i)))).isSome := by
change (l.getDual? i).isSome
have h1 : i.1 ∈ l.withUniqueDual := by
have hi2 := i.2
simp only [withUniqueDualLT, Finset.mem_filter] at hi2
exact hi2.1
exact mem_withUniqueDual_isSome l.toIndexList (↑i) h1
@[simp]
lemma contrEquiv_inl_inr_eq (i : l.withUniqueDualLT) :
(l.contrEquiv (Sum.inl (Sum.inr i))) =
(l.getDual? i.1).get (l.contrEquiv_inl_inl_isSome i) := by
rfl
@[simp]
lemma contrEquiv_inl_inl_eq (i : l.withUniqueDualLT) :
(l.contrEquiv (Sum.inl (Sum.inl i))) = i := by
rfl
lemma contrEquiv_colorMapIso :
ColorMap.MapIso (Equiv.refl (Fin l.contr.length))
(ColorMap.contr l.contrEquiv l.colorMap) l.contr.colorMap := by
simp [ColorMap.MapIso, ColorMap.contr]
funext i
simp [contr]
rfl
lemma contrEquiv_contrCond : ColorMap.ContrCond l.contrEquiv l.colorMap := by
simp only [ColorMap.ContrCond]
funext i
simp only [Function.comp_apply, contrEquiv_inl_inl_eq, contrEquiv_inl_inr_eq]
have h1 := l.dual_color
rw [ColorCond.iff_on_isSome] at h1
exact (h1 i.1 _).symm
@[simp]
lemma contrEquiv_on_withDual_empty (i : Fin l.contr.length) (h : l.withDual = ∅) :
l.contrEquiv (Sum.inr i) = Fin.cast (by simp [h]) i := by
simp [contrEquiv]
change l.dualEquiv (Sum.inr ((Fin.castOrderIso _).toEquiv i)) = _
simp [dualEquiv, withoutDualEquiv]
have h : l.withoutDual = Finset.univ := by
have hx := l.withDual_union_withoutDual
simp_all
simp [h]
rw [orderEmbOfFin_univ]
· rfl
· rw [h]
simp
end ColorIndexList
end IndexNotation

View file

@ -3,7 +3,7 @@ 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.LorentzTensor.IndexNotation.Color
import HepLean.SpaceTime.LorentzTensor.IndexNotation.ColorIndexList.Contraction
import HepLean.SpaceTime.LorentzTensor.Basic
import Init.Data.List.Lemmas
/-!

View file

@ -170,12 +170,18 @@ lemma withUniqueDual_eq_withDual_filter_id_fin (h : l.withUniqueDual = l.withDua
omega
section filterID
lemma filter_id_of_countP_zero {i : Fin l.length}
(h1 : l.val.countP (fun J => (l.val.get i).id = J.id) = 0) :
l.val.filter (fun J => (l.val.get i).id = J.id) = [] := by
rw [List.countP_eq_length_filter, List.length_eq_zero] at h1
exact h1
lemma filter_of_countP_zero {I : Index X} (h1 : l.val.countP (fun J => I.id = J.id) = 0) :
l.val.filter (fun J => I.id = J.id) = [] := by
rw [List.countP_eq_length_filter, List.length_eq_zero] at h1
exact h1
lemma filter_id_of_countP_one {i : Fin l.length}
(h1 : l.val.countP (fun J => (l.val.get i).id = J.id) = 1) :
l.val.filter (fun J => (l.val.get i).id = J.id) = [l.val.get i] := by

View file

@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzTensor.IndexNotation.Color
import HepLean.SpaceTime.LorentzTensor.IndexNotation.Relations
import HepLean.SpaceTime.LorentzTensor.IndexNotation.ColorIndexList.Relations
import HepLean.SpaceTime.LorentzTensor.IndexNotation.ColorIndexList.Append
import HepLean.SpaceTime.LorentzTensor.Basic
import HepLean.SpaceTime.LorentzTensor.RisingLowering
import HepLean.SpaceTime.LorentzTensor.Contraction