refactor: index notation

This commit is contained in:
jstoobysmith 2024-08-26 15:23:38 -04:00
parent 4f9b572274
commit 6b0ecc4405
6 changed files with 1034 additions and 386 deletions

View file

@ -169,387 +169,4 @@ def id (s : Index X) : Nat := s.tailNat.foldl (fun a b => 10 * a + b) 0
end Index
/-!
## List of indices
-/
/-- The type of lists of indices. -/
structure IndexList where
/-- The list of index values. For example `['ᵘ¹','ᵘ²','ᵤ₁']`. -/
val : List (Index X)
namespace IndexList
variable {X : Type} [IndexNotation X] [Fintype X] [DecidableEq X]
variable (l : IndexList X)
/-- The number of indices in an index list. -/
def length : := l.val.length
lemma ext (h : l.val = l2.val) : l = l2 := by
cases l
cases l2
simp_all
/-- The index list constructed by prepending an index to the list. -/
def cons (i : Index X) : IndexList X := {val := i :: l.val}
@[simp]
lemma cons_val (i : Index X) : (l.cons i).val = i :: l.val := by
rfl
@[simp]
lemma cons_length (i : Index X) : (l.cons i).length = l.length + 1 := by
rfl
/-- The tail of an index list. That is, the index list with the first index dropped. -/
def tail : IndexList X := {val := l.val.tail}
@[simp]
lemma tail_val : l.tail.val = l.val.tail := by
rfl
/-- The first index in a non-empty index list. -/
def head (h : l ≠ {val := ∅}) : Index X := l.val.head (by cases' l; simpa using h)
lemma head_cons_tail (h : l ≠ {val := ∅}) : l = (l.tail.cons (l.head h)) := by
apply ext
simp only [cons_val, tail_val]
simp only [head, List.head_cons_tail]
lemma induction {P : IndexList X → Prop } (h_nil : P {val := ∅})
(h_cons : ∀ (x : Index X) (xs : IndexList X), P xs → P (xs.cons x)) (l : IndexList X) : P l := by
cases' l with val
induction val with
| nil => exact h_nil
| cons x xs ih =>
exact h_cons x ⟨xs⟩ ih
/-- The map of from `Fin s.numIndices` into colors associated to an index list. -/
def colorMap : Fin l.length → X :=
fun i => (l.val.get i).toColor
/-- The map of from `Fin s.numIndices` into the natural numbers associated to an index list. -/
def idMap : Fin l.length → Nat :=
fun i => (l.val.get i).id
lemma idMap_cast {l1 l2 : IndexList X} (h : l1 = l2) (i : Fin l1.length) :
l1.idMap i = l2.idMap (Fin.cast (by rw [h]) i) := by
subst h
rfl
/-- Given a list of indices a subset of `Fin l.numIndices × Index X`
of pairs of positions in `l` and the corresponding item in `l`. -/
def toPosSet (l : IndexList X) : Set (Fin l.length × Index X) :=
{(i, l.val.get i) | i : Fin l.length}
/-- Equivalence between `toPosSet` and `Fin l.numIndices`. -/
def toPosSetEquiv (l : IndexList X) : l.toPosSet ≃ Fin l.length where
toFun := fun x => x.1.1
invFun := fun x => ⟨(x, l.val.get x), by simp [toPosSet]⟩
left_inv x := by
have hx := x.prop
simp [toPosSet] at hx
simp only [List.get_eq_getElem]
obtain ⟨i, hi⟩ := hx
have hi2 : i = x.1.1 := by
obtain ⟨val, property⟩ := x
obtain ⟨fst, snd⟩ := val
simp_all only [Prod.mk.injEq]
subst hi2
simp_all only [Subtype.coe_eta]
right_inv := by
intro x
rfl
lemma toPosSet_is_finite (l : IndexList X) : l.toPosSet.Finite :=
Finite.intro l.toPosSetEquiv
instance : Fintype l.toPosSet where
elems := Finset.map l.toPosSetEquiv.symm.toEmbedding Finset.univ
complete := by
intro x
simp_all only [Finset.mem_map_equiv, Equiv.symm_symm, Finset.mem_univ]
/-- Given a list of indices a finite set of `Fin l.length × Index X`
of pairs of positions in `l` and the corresponding item in `l`. -/
def toPosFinset (l : IndexList X) : Finset (Fin l.length × Index X) :=
l.toPosSet.toFinset
/-- The construction of a list of indices from a map
from `Fin n` to `Index X`. -/
def fromFinMap {n : } (f : Fin n → Index X) : IndexList X where
val := (Fin.list n).map f
@[simp]
lemma fromFinMap_numIndices {n : } (f : Fin n → Index X) :
(fromFinMap f).length = n := by
simp [fromFinMap, length]
/-!
## Appending index lists.
-/
section append
variable {X : Type} [IndexNotation X] [Fintype X] [DecidableEq X]
variable (l l2 l3 : IndexList X)
instance : HAppend (IndexList X) (IndexList X) (IndexList X) where
hAppend := fun l l2 => {val := l.val ++ l2.val}
@[simp]
lemma cons_append (i : Index X) : (l.cons i) ++ l2 = (l ++ l2).cons i := by
rfl
@[simp]
lemma append_length : (l ++ l2).length = l.length + l2.length := by
simp [IndexList.length]
exact List.length_append l.val l2.val
lemma append_assoc : l ++ l2 ++ l3 = l ++ (l2 ++ l3) := by
apply ext
change l.val ++ l2.val ++ l3.val = l.val ++ (l2.val ++ l3.val)
exact List.append_assoc l.val l2.val l3.val
/-- An equivalence between the sum of the types of indices of `l` an `l2` and the type
of indices of the joined index list `l ++ l2`. -/
def appendEquiv {l l2 : IndexList X} : Fin l.length ⊕ Fin l2.length ≃ Fin (l ++ l2).length :=
finSumFinEquiv.trans (Fin.castOrderIso (List.length_append _ _).symm).toEquiv
/-- The inclusion of the indices of `l` into the indices of `l ++ l2`. -/
def appendInl : Fin l.length ↪ Fin (l ++ l2).length where
toFun := appendEquiv ∘ Sum.inl
inj' := by
intro i j h
simp [Function.comp] at h
exact h
/-- The inclusion of the indices of `l2` into the indices of `l ++ l2`. -/
def appendInr : Fin l2.length ↪ Fin (l ++ l2).length where
toFun := appendEquiv ∘ Sum.inr
inj' := by
intro i j h
simp [Function.comp] at h
exact h
@[simp]
lemma appendInl_appendEquiv :
(l.appendInl l2).trans appendEquiv.symm.toEmbedding =
{toFun := Sum.inl, inj' := Sum.inl_injective} := by
ext i
simp [appendInl]
@[simp]
lemma appendInr_appendEquiv :
(l.appendInr l2).trans appendEquiv.symm.toEmbedding =
{toFun := Sum.inr, inj' := Sum.inr_injective} := by
ext i
simp [appendInr]
@[simp]
lemma append_val {l l2 : IndexList X} : (l ++ l2).val = l.val ++ l2.val := by
rfl
@[simp]
lemma idMap_append_inl {l l2 : IndexList X} (i : Fin l.length) :
(l ++ l2).idMap (appendEquiv (Sum.inl i)) = l.idMap i := by
simp [appendEquiv, idMap]
rw [List.getElem_append_left]
rfl
@[simp]
lemma idMap_append_inr {l l2 : IndexList X} (i : Fin l2.length) :
(l ++ l2).idMap (appendEquiv (Sum.inr i)) = l2.idMap i := by
simp [appendEquiv, idMap, IndexList.length]
rw [List.getElem_append_right]
· simp only [Nat.add_sub_cancel_left]
· omega
· omega
@[simp]
lemma colorMap_append_inl {l l2 : IndexList X} (i : Fin l.length) :
(l ++ l2).colorMap (appendEquiv (Sum.inl i)) = l.colorMap i := by
simp [appendEquiv, colorMap, IndexList.length]
rw [List.getElem_append_left]
@[simp]
lemma colorMap_append_inl' :
(l ++ l2).colorMap ∘ appendEquiv ∘ Sum.inl = l.colorMap := by
funext i
simp
@[simp]
lemma colorMap_append_inr {l l2 : IndexList X} (i : Fin l2.length) :
(l ++ l2).colorMap (appendEquiv (Sum.inr i)) = l2.colorMap i := by
simp [appendEquiv, colorMap, IndexList.length]
rw [List.getElem_append_right]
· simp only [Nat.add_sub_cancel_left]
· omega
· omega
@[simp]
lemma colorMap_append_inr' :
(l ++ l2).colorMap ∘ appendEquiv ∘ Sum.inr = l2.colorMap := by
funext i
simp
lemma colorMap_sumELim (l1 l2 : IndexList X) :
Sum.elim l1.colorMap l2.colorMap =
(l1 ++ l2).colorMap ∘ appendEquiv := by
funext x
match x with
| Sum.inl i => simp
| Sum.inr i => simp
end append
/-!
## countId
-/
/-- The number of times the id of an index `I` appears in a list of indices `l`. -/
def countId (I : Index X) : :=
l.val.countP (fun J => I.id = J.id)
@[simp]
lemma countId_append (I : Index X) : (l ++ l2).countId I = l.countId I + l2.countId I := by
simp [countId]
lemma countId_eq_length_filter (I : Index X) :
l.countId I = (l.val.filter (fun J => I.id = J.id)).length := by
simp [countId]
rw [List.countP_eq_length_filter]
lemma countId_index_neq_zero (i : Fin l.length) : l.countId (l.val.get i) ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [List.length_eq_zero] at hn
have hm : l.val.get i ∈ List.filter (fun J => decide ((l.val.get i).id = J.id)) l.val := by
simpa using List.getElem_mem l.val i.1 i.isLt
rw [hn] at hm
simp at hm
lemma countId_append_symm (I : Index X) : (l ++ l2).countId I = (l2 ++ l).countId I := by
simp only [countId_append]
omega
lemma countId_eq_one_append_mem_right_self_eq_one {I : Index X} (hI : I ∈ l2.val)
(h : (l ++ l2).countId I = 1) : l2.countId I = 1 := by
simp at h
have hmem : I ∈ l2.val.filter (fun J => I.id = J.id) := by
simp [List.mem_filter, decide_True, and_true, hI]
have h1 : l2.countId I ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [@List.length_eq_zero] at hn
rw [hn] at hmem
simp at hmem
omega
lemma countId_eq_one_append_mem_right_other_eq_zero {I : Index X} (hI : I ∈ l2.val)
(h : (l ++ l2).countId I = 1) : l.countId I = 0 := by
simp at h
have hmem : I ∈ l2.val.filter (fun J => I.id = J.id) := by
simp [List.mem_filter, decide_True, and_true, hI]
have h1 : l2.countId I ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [@List.length_eq_zero] at hn
rw [hn] at hmem
simp at hmem
omega
@[simp]
lemma countId_cons_eq_two {I : Index X} :
(l.cons I).countId I = 2 ↔ l.countId I = 1 := by
simp [countId]
lemma countId_congr {I J : Index X} (h : I.id = J.id) : l.countId I = l.countId J := by
simp [countId, h]
lemma countId_neq_zero_mem (I : Index X) (h : l.countId I ≠ 0) :
∃ I', I' ∈ l.val ∧ I.id = I'.id := by
rw [countId_eq_length_filter] at h
have h' := List.isEmpty_iff_length_eq_zero.mp.mt h
simp only at h'
have h'' := eq_false_of_ne_true h'
rw [List.isEmpty_false_iff_exists_mem] at h''
obtain ⟨I', hI'⟩ := h''
simp only [List.mem_filter, decide_eq_true_eq] at hI'
exact ⟨I', hI'⟩
lemma countId_mem (I : Index X) (hI : I ∈ l.val) : l.countId I ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [List.length_eq_zero] at hn
have hIme : I ∈ List.filter (fun J => decide (I.id = J.id)) l.val := by
simp [hI]
rw [hn] at hIme
simp at hIme
/-!
## Filter id
-/
/-! TODO: Replace with Mathlib lemma. -/
lemma filter_sort_comm {n : } (s : Finset (Fin n)) (p : Fin n → Prop) [DecidablePred p] :
List.filter p (Finset.sort (fun i j => i ≤ j) s) =
Finset.sort (fun i j => i ≤ j) (Finset.filter p s) := by
simp [Finset.filter, Finset.sort]
have : ∀ (m : Multiset (Fin n)), List.filter p (Multiset.sort (fun i j => i ≤ j) m) =
Multiset.sort (fun i j => i ≤ j) (Multiset.filter p m) := by
apply Quot.ind
intro m
simp [List.mergeSort]
have h1 : List.Sorted (fun i j => i ≤ j) (List.filter (fun b => decide (p b))
(List.mergeSort (fun i j => i ≤ j) m)) := by
simp [List.Sorted]
rw [List.pairwise_filter]
rw [@List.pairwise_iff_get]
intro i j h1 _ _
have hs : List.Sorted (fun i j => i ≤ j) (List.mergeSort (fun i j => i ≤ j) m) := by
exact List.sorted_mergeSort (fun i j => i ≤ j) m
simp [List.Sorted] at hs
rw [List.pairwise_iff_get] at hs
exact hs i j h1
have hp1 : (List.mergeSort (fun i j => i ≤ j) m).Perm m := by
exact List.perm_mergeSort (fun i j => i ≤ j) m
have hp2 : (List.filter (fun b => decide (p b)) ((List.mergeSort (fun i j => i ≤ j) m))).Perm
(List.filter (fun b => decide (p b)) m) := by
exact List.Perm.filter (fun b => decide (p b)) hp1
have hp3 : (List.filter (fun b => decide (p b)) m).Perm
(List.mergeSort (fun i j => i ≤ j) (List.filter (fun b => decide (p b)) m)) := by
exact List.Perm.symm (List.perm_mergeSort (fun i j => i ≤ j)
(List.filter (fun b => decide (p b)) m))
have hp4 := hp2.trans hp3
refine List.eq_of_perm_of_sorted hp4 h1 ?_
exact List.sorted_mergeSort (fun i j => i ≤ j) (List.filter (fun b => decide (p b)) m)
exact this s.val
lemma filter_id_eq_sort (i : Fin l.length) : l.val.filter (fun J => (l.val.get i).id = J.id) =
List.map l.val.get (Finset.sort (fun i j => i ≤ j)
(Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ)) := by
have h1 := (List.finRange_map_get l.val).symm
have h2 : l.val = List.map l.val.get (Finset.sort (fun i j => i ≤ j) Finset.univ) := by
nth_rewrite 1 [h1, (Fin.sort_univ l.val.length).symm]
rfl
nth_rewrite 3 [h2]
rw [List.filter_map]
apply congrArg
rw [← filter_sort_comm]
apply List.filter_congr
intro x _
simp [idMap]
end IndexList
end IndexNotation

View file

@ -11,7 +11,9 @@ import Init.Data.List.Lemmas
# Appending two ColorIndexLists
We define the contraction of ColorIndexLists.
We define conditional appending of `ColorIndexList`'s.
It is conditional on `AppendCond` being true, which we define.
-/

View file

@ -0,0 +1,312 @@
/-
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.Basic
/-!
# Index lists
i.e. lists of indices.
-/
namespace IndexNotation
variable (X : Type) [IndexNotation X]
variable [Fintype X] [DecidableEq X]
/-- The type of lists of indices. -/
structure IndexList where
/-- The list of index values. For example `['ᵘ¹','ᵘ²','ᵤ₁']`. -/
val : List (Index X)
namespace IndexList
variable {X : Type} [IndexNotation X] [Fintype X] [DecidableEq X]
variable (l : IndexList X)
/-- The number of indices in an index list. -/
def length : := l.val.length
lemma ext (h : l.val = l2.val) : l = l2 := by
cases l
cases l2
simp_all
/-- The index list constructed by prepending an index to the list. -/
def cons (i : Index X) : IndexList X := {val := i :: l.val}
@[simp]
lemma cons_val (i : Index X) : (l.cons i).val = i :: l.val := by
rfl
@[simp]
lemma cons_length (i : Index X) : (l.cons i).length = l.length + 1 := by
rfl
/-- The tail of an index list. That is, the index list with the first index dropped. -/
def tail : IndexList X := {val := l.val.tail}
@[simp]
lemma tail_val : l.tail.val = l.val.tail := by
rfl
/-- The first index in a non-empty index list. -/
def head (h : l ≠ {val := ∅}) : Index X := l.val.head (by cases' l; simpa using h)
lemma head_cons_tail (h : l ≠ {val := ∅}) : l = (l.tail.cons (l.head h)) := by
apply ext
simp only [cons_val, tail_val]
simp only [head, List.head_cons_tail]
lemma induction {P : IndexList X → Prop } (h_nil : P {val := ∅})
(h_cons : ∀ (x : Index X) (xs : IndexList X), P xs → P (xs.cons x)) (l : IndexList X) : P l := by
cases' l with val
induction val with
| nil => exact h_nil
| cons x xs ih =>
exact h_cons x ⟨xs⟩ ih
/-- The map of from `Fin s.numIndices` into colors associated to an index list. -/
def colorMap : Fin l.length → X :=
fun i => (l.val.get i).toColor
/-- The map of from `Fin s.numIndices` into the natural numbers associated to an index list. -/
def idMap : Fin l.length → Nat :=
fun i => (l.val.get i).id
lemma idMap_cast {l1 l2 : IndexList X} (h : l1 = l2) (i : Fin l1.length) :
l1.idMap i = l2.idMap (Fin.cast (by rw [h]) i) := by
subst h
rfl
/-- Given a list of indices a subset of `Fin l.numIndices × Index X`
of pairs of positions in `l` and the corresponding item in `l`. -/
def toPosSet (l : IndexList X) : Set (Fin l.length × Index X) :=
{(i, l.val.get i) | i : Fin l.length}
/-- Equivalence between `toPosSet` and `Fin l.numIndices`. -/
def toPosSetEquiv (l : IndexList X) : l.toPosSet ≃ Fin l.length where
toFun := fun x => x.1.1
invFun := fun x => ⟨(x, l.val.get x), by simp [toPosSet]⟩
left_inv x := by
have hx := x.prop
simp [toPosSet] at hx
simp only [List.get_eq_getElem]
obtain ⟨i, hi⟩ := hx
have hi2 : i = x.1.1 := by
obtain ⟨val, property⟩ := x
obtain ⟨fst, snd⟩ := val
simp_all only [Prod.mk.injEq]
subst hi2
simp_all only [Subtype.coe_eta]
right_inv := by
intro x
rfl
lemma toPosSet_is_finite (l : IndexList X) : l.toPosSet.Finite :=
Finite.intro l.toPosSetEquiv
instance : Fintype l.toPosSet where
elems := Finset.map l.toPosSetEquiv.symm.toEmbedding Finset.univ
complete := by
intro x
simp_all only [Finset.mem_map_equiv, Equiv.symm_symm, Finset.mem_univ]
/-- Given a list of indices a finite set of `Fin l.length × Index X`
of pairs of positions in `l` and the corresponding item in `l`. -/
def toPosFinset (l : IndexList X) : Finset (Fin l.length × Index X) :=
l.toPosSet.toFinset
/-- The construction of a list of indices from a map
from `Fin n` to `Index X`. -/
def fromFinMap {n : } (f : Fin n → Index X) : IndexList X where
val := (Fin.list n).map f
@[simp]
lemma fromFinMap_numIndices {n : } (f : Fin n → Index X) :
(fromFinMap f).length = n := by
simp [fromFinMap, length]
/-!
## Appending index lists.
-/
section append
variable {X : Type} [IndexNotation X] [Fintype X] [DecidableEq X]
variable (l l2 l3 : IndexList X)
instance : HAppend (IndexList X) (IndexList X) (IndexList X) where
hAppend := fun l l2 => {val := l.val ++ l2.val}
@[simp]
lemma cons_append (i : Index X) : (l.cons i) ++ l2 = (l ++ l2).cons i := by
rfl
@[simp]
lemma append_length : (l ++ l2).length = l.length + l2.length := by
simp [IndexList.length]
exact List.length_append l.val l2.val
lemma append_assoc : l ++ l2 ++ l3 = l ++ (l2 ++ l3) := by
apply ext
change l.val ++ l2.val ++ l3.val = l.val ++ (l2.val ++ l3.val)
exact List.append_assoc l.val l2.val l3.val
/-- An equivalence between the sum of the types of indices of `l` an `l2` and the type
of indices of the joined index list `l ++ l2`. -/
def appendEquiv {l l2 : IndexList X} : Fin l.length ⊕ Fin l2.length ≃ Fin (l ++ l2).length :=
finSumFinEquiv.trans (Fin.castOrderIso (List.length_append _ _).symm).toEquiv
/-- The inclusion of the indices of `l` into the indices of `l ++ l2`. -/
def appendInl : Fin l.length ↪ Fin (l ++ l2).length where
toFun := appendEquiv ∘ Sum.inl
inj' := by
intro i j h
simp [Function.comp] at h
exact h
/-- The inclusion of the indices of `l2` into the indices of `l ++ l2`. -/
def appendInr : Fin l2.length ↪ Fin (l ++ l2).length where
toFun := appendEquiv ∘ Sum.inr
inj' := by
intro i j h
simp [Function.comp] at h
exact h
@[simp]
lemma appendInl_appendEquiv :
(l.appendInl l2).trans appendEquiv.symm.toEmbedding =
{toFun := Sum.inl, inj' := Sum.inl_injective} := by
ext i
simp [appendInl]
@[simp]
lemma appendInr_appendEquiv :
(l.appendInr l2).trans appendEquiv.symm.toEmbedding =
{toFun := Sum.inr, inj' := Sum.inr_injective} := by
ext i
simp [appendInr]
@[simp]
lemma append_val {l l2 : IndexList X} : (l ++ l2).val = l.val ++ l2.val := by
rfl
@[simp]
lemma idMap_append_inl {l l2 : IndexList X} (i : Fin l.length) :
(l ++ l2).idMap (appendEquiv (Sum.inl i)) = l.idMap i := by
simp [appendEquiv, idMap]
rw [List.getElem_append_left]
rfl
@[simp]
lemma idMap_append_inr {l l2 : IndexList X} (i : Fin l2.length) :
(l ++ l2).idMap (appendEquiv (Sum.inr i)) = l2.idMap i := by
simp [appendEquiv, idMap, IndexList.length]
rw [List.getElem_append_right]
· simp only [Nat.add_sub_cancel_left]
· omega
· omega
@[simp]
lemma colorMap_append_inl {l l2 : IndexList X} (i : Fin l.length) :
(l ++ l2).colorMap (appendEquiv (Sum.inl i)) = l.colorMap i := by
simp [appendEquiv, colorMap, IndexList.length]
rw [List.getElem_append_left]
@[simp]
lemma colorMap_append_inl' :
(l ++ l2).colorMap ∘ appendEquiv ∘ Sum.inl = l.colorMap := by
funext i
simp
@[simp]
lemma colorMap_append_inr {l l2 : IndexList X} (i : Fin l2.length) :
(l ++ l2).colorMap (appendEquiv (Sum.inr i)) = l2.colorMap i := by
simp [appendEquiv, colorMap, IndexList.length]
rw [List.getElem_append_right]
· simp only [Nat.add_sub_cancel_left]
· omega
· omega
@[simp]
lemma colorMap_append_inr' :
(l ++ l2).colorMap ∘ appendEquiv ∘ Sum.inr = l2.colorMap := by
funext i
simp
lemma colorMap_sumELim (l1 l2 : IndexList X) :
Sum.elim l1.colorMap l2.colorMap =
(l1 ++ l2).colorMap ∘ appendEquiv := by
funext x
match x with
| Sum.inl i => simp
| Sum.inr i => simp
end append
/-!
## Filter id
-/
/-! TODO: Replace with Mathlib lemma. -/
lemma filter_sort_comm {n : } (s : Finset (Fin n)) (p : Fin n → Prop) [DecidablePred p] :
List.filter p (Finset.sort (fun i j => i ≤ j) s) =
Finset.sort (fun i j => i ≤ j) (Finset.filter p s) := by
simp [Finset.filter, Finset.sort]
have : ∀ (m : Multiset (Fin n)), List.filter p (Multiset.sort (fun i j => i ≤ j) m) =
Multiset.sort (fun i j => i ≤ j) (Multiset.filter p m) := by
apply Quot.ind
intro m
simp [List.mergeSort]
have h1 : List.Sorted (fun i j => i ≤ j) (List.filter (fun b => decide (p b))
(List.mergeSort (fun i j => i ≤ j) m)) := by
simp [List.Sorted]
rw [List.pairwise_filter]
rw [@List.pairwise_iff_get]
intro i j h1 _ _
have hs : List.Sorted (fun i j => i ≤ j) (List.mergeSort (fun i j => i ≤ j) m) := by
exact List.sorted_mergeSort (fun i j => i ≤ j) m
simp [List.Sorted] at hs
rw [List.pairwise_iff_get] at hs
exact hs i j h1
have hp1 : (List.mergeSort (fun i j => i ≤ j) m).Perm m := by
exact List.perm_mergeSort (fun i j => i ≤ j) m
have hp2 : (List.filter (fun b => decide (p b)) ((List.mergeSort (fun i j => i ≤ j) m))).Perm
(List.filter (fun b => decide (p b)) m) := by
exact List.Perm.filter (fun b => decide (p b)) hp1
have hp3 : (List.filter (fun b => decide (p b)) m).Perm
(List.mergeSort (fun i j => i ≤ j) (List.filter (fun b => decide (p b)) m)) := by
exact List.Perm.symm (List.perm_mergeSort (fun i j => i ≤ j)
(List.filter (fun b => decide (p b)) m))
have hp4 := hp2.trans hp3
refine List.eq_of_perm_of_sorted hp4 h1 ?_
exact List.sorted_mergeSort (fun i j => i ≤ j) (List.filter (fun b => decide (p b)) m)
exact this s.val
lemma filter_id_eq_sort (i : Fin l.length) : l.val.filter (fun J => (l.val.get i).id = J.id) =
List.map l.val.get (Finset.sort (fun i j => i ≤ j)
(Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ)) := by
have h1 := (List.finRange_map_get l.val).symm
have h2 : l.val = List.map l.val.get (Finset.sort (fun i j => i ≤ j) Finset.univ) := by
nth_rewrite 1 [h1, (Fin.sort_univ l.val.length).symm]
rfl
nth_rewrite 3 [h2]
rw [List.filter_map]
apply congrArg
rw [← filter_sort_comm]
apply List.filter_congr
intro x _
simp [idMap]
end IndexList
end IndexNotation

View file

@ -0,0 +1,339 @@
/-
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.IndexList.Duals
/-!
# Counting ids
-/
namespace IndexNotation
namespace IndexList
variable {X : Type} [IndexNotation X] [Fintype X] [DecidableEq X]
variable (l l2 l3 : IndexList X)
/-!
## countId
-/
/-- The number of times the id of an index `I` appears in a list of indices `l`. -/
def countId (I : Index X) : :=
l.val.countP (fun J => I.id = J.id)
/-!
## Basic properties
-/
@[simp]
lemma countId_append (I : Index X) : (l ++ l2).countId I = l.countId I + l2.countId I := by
simp [countId]
lemma countId_eq_length_filter (I : Index X) :
l.countId I = (l.val.filter (fun J => I.id = J.id)).length := by
simp [countId]
rw [List.countP_eq_length_filter]
lemma countId_index_neq_zero (i : Fin l.length) : l.countId (l.val.get i) ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [List.length_eq_zero] at hn
have hm : l.val.get i ∈ List.filter (fun J => decide ((l.val.get i).id = J.id)) l.val := by
simpa using List.getElem_mem l.val i.1 i.isLt
rw [hn] at hm
simp at hm
lemma countId_append_symm (I : Index X) : (l ++ l2).countId I = (l2 ++ l).countId I := by
simp only [countId_append]
omega
lemma countId_eq_one_append_mem_right_self_eq_one {I : Index X} (hI : I ∈ l2.val)
(h : (l ++ l2).countId I = 1) : l2.countId I = 1 := by
simp at h
have hmem : I ∈ l2.val.filter (fun J => I.id = J.id) := by
simp [List.mem_filter, decide_True, and_true, hI]
have h1 : l2.countId I ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [@List.length_eq_zero] at hn
rw [hn] at hmem
simp at hmem
omega
lemma countId_eq_one_append_mem_right_other_eq_zero {I : Index X} (hI : I ∈ l2.val)
(h : (l ++ l2).countId I = 1) : l.countId I = 0 := by
simp at h
have hmem : I ∈ l2.val.filter (fun J => I.id = J.id) := by
simp [List.mem_filter, decide_True, and_true, hI]
have h1 : l2.countId I ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [@List.length_eq_zero] at hn
rw [hn] at hmem
simp at hmem
omega
@[simp]
lemma countId_cons_eq_two {I : Index X} :
(l.cons I).countId I = 2 ↔ l.countId I = 1 := by
simp [countId]
lemma countId_congr {I J : Index X} (h : I.id = J.id) : l.countId I = l.countId J := by
simp [countId, h]
lemma countId_neq_zero_mem (I : Index X) (h : l.countId I ≠ 0) :
∃ I', I' ∈ l.val ∧ I.id = I'.id := by
rw [countId_eq_length_filter] at h
have h' := List.isEmpty_iff_length_eq_zero.mp.mt h
simp only at h'
have h'' := eq_false_of_ne_true h'
rw [List.isEmpty_false_iff_exists_mem] at h''
obtain ⟨I', hI'⟩ := h''
simp only [List.mem_filter, decide_eq_true_eq] at hI'
exact ⟨I', hI'⟩
lemma countId_mem (I : Index X) (hI : I ∈ l.val) : l.countId I ≠ 0 := by
rw [countId_eq_length_filter]
by_contra hn
rw [List.length_eq_zero] at hn
have hIme : I ∈ List.filter (fun J => decide (I.id = J.id)) l.val := by
simp [hI]
rw [hn] at hIme
simp at hIme
lemma countId_get_other (i : Fin l.length) : l2.countId (l.val.get i) =
(List.finRange l2.length).countP (fun j => l.AreDualInOther l2 i j) := by
rw [countId_eq_length_filter]
rw [List.countP_eq_length_filter]
have hl2 : l2.val = List.map l2.val.get (List.finRange l2.length) := by
simp only [length, List.finRange_map_get]
nth_rewrite 1 [hl2]
rw [List.filter_map, List.length_map]
apply congrArg
refine List.filter_congr (fun j _ => ?_)
simp [AreDualInOther, idMap]
/-! TODO: Replace with mathlib lemma. -/
lemma filter_finRange (i : Fin l.length) : List.filter (fun j => i = j) (List.finRange l.length) = [i] := by
have h3 : (List.filter (fun j => i = j) (List.finRange l.length)).length = 1 := by
rw [← List.countP_eq_length_filter]
trans List.count i (List.finRange l.length)
· simp [List.count]
apply List.countP_congr (fun j _ => ?_)
simp
exact eq_comm
· exact List.nodup_iff_count_eq_one.mp (List.nodup_finRange l.length) _ (List.mem_finRange i)
have h4 : i ∈ List.filter (fun j => i = j) (List.finRange l.length) := by
simp
rw [@List.length_eq_one] at h3
obtain ⟨a, ha⟩ := h3
rw [ha] at h4
simp at h4
subst h4
exact ha
lemma countId_get (i : Fin l.length) : l.countId (l.val.get i) =
(List.finRange l.length).countP (fun j => l.AreDualInSelf i j) + 1 := by
rw [countId_get_other l l]
have h1 : (List.finRange l.length).countP (fun j => l.AreDualInSelf i j)
= ((List.finRange l.length).filter (fun j => l.AreDualInOther l i j)).countP
(fun j => ¬ i = j) := by
rw [List.countP_filter]
refine List.countP_congr ?_
intro j _
simp [AreDualInSelf, AreDualInOther]
rw [h1]
have h1 := List.length_eq_countP_add_countP (fun j => i = j) ((List.finRange l.length).filter (fun j => l.AreDualInOther l i j))
have h2 : List.countP (fun j => i = j)
(List.filter (fun j => l.AreDualInOther l i j) (List.finRange l.length)) =
List.countP (fun j => l.AreDualInOther l i j)
(List.filter (fun j => i = j) (List.finRange l.length)) := by
rw [List.countP_filter, List.countP_filter]
refine List.countP_congr (fun j _ => ?_)
simpa using And.comm
have ha := l.filter_finRange
rw [ha] at h2
rw [h2] at h1
rw [List.countP_eq_length_filter, h1, add_comm]
simp
simp [List.countP, List.countP.go, AreDualInOther]
/-!
## Duals and countId
-/
lemma countId_gt_zero_of_mem_withDual (i : Fin l.length) (h : i ∈ l.withDual) :
1 < l.countId (l.val.get i) := by
rw [countId_get]
by_contra hn
simp at hn
rw [List.countP_eq_length_filter, List.length_eq_zero] at hn
rw [mem_withDual_iff_exists] at h
obtain ⟨j, hj⟩ := h
have hjmem : j ∈ (List.finRange l.length).filter (fun j => decide (l.AreDualInSelf i j)) := by
simpa using hj
rw [hn] at hjmem
simp at hjmem
lemma countId_of_not_mem_withDual (i : Fin l.length)(h : i ∉ l.withDual) :
l.countId (l.val.get i) = 1 := by
rw [countId_get]
simp only [add_left_eq_self]
rw [List.countP_eq_length_filter]
simp only [List.length_eq_zero]
rw [List.filter_eq_nil]
simp only [List.mem_finRange, decide_eq_true_eq, true_implies]
rw [mem_withDual_iff_exists] at h
simpa using h
lemma mem_withDual_iff_countId_gt_one (i : Fin l.length) :
i ∈ l.withDual ↔ 1 < l.countId (l.val.get i) := by
refine Iff.intro (fun h => countId_gt_zero_of_mem_withDual l i h) (fun h => ?_)
by_contra hn
have hn' := countId_of_not_mem_withDual l i hn
omega
lemma countId_neq_zero_of_mem_withDualInOther (i : Fin l.length) (h : i ∈ l.withDualInOther l2) :
l2.countId (l.val.get i) ≠ 0 := by
rw [mem_withInDualOther_iff_exists] at h
rw [countId_eq_length_filter]
by_contra hn
rw [List.length_eq_zero] at hn
obtain ⟨j, hj⟩ := h
have hjmem : l2.val.get j ∈ List.filter (fun J => decide ((l.val.get i).id = J.id)) l2.val := by
simp
apply And.intro
· exact List.getElem_mem l2.val (↑j) j.isLt
· simpa [AreDualInOther] using hj
rw [hn] at hjmem
simp at hjmem
lemma countId_of_not_mem_withDualInOther (i : Fin l.length) (h : i ∉ l.withDualInOther l2) :
l2.countId (l.val.get i) = 0 := by
by_contra hn
rw [countId_eq_length_filter] at hn
rw [← List.isEmpty_iff_length_eq_zero] at hn
have hx := eq_false_of_ne_true hn
rw [List.isEmpty_false_iff_exists_mem] at hx
obtain ⟨j, hj⟩ := hx
have hjmem : j ∈ l2.val := List.mem_of_mem_filter hj
have hj' : l2.val.indexOf j < l2.length := List.indexOf_lt_length.mpr hjmem
have hjid : l2.val.get ⟨l2.val.indexOf j, hj'⟩ = j := List.indexOf_get hj'
rw [mem_withInDualOther_iff_exists] at h
simp at h
have hj' := h ⟨l2.val.indexOf j, hj'⟩
simp [AreDualInOther, idMap] at hj'
simp at hj
simp_all only [List.get_eq_getElem, List.isEmpty_eq_true, List.getElem_indexOf, not_true_eq_false]
lemma mem_withDualInOther_iff_countId_neq_zero (i : Fin l.length) :
i ∈ l.withDualInOther l2 ↔ l2.countId (l.val.get i) ≠ 0 := by
refine Iff.intro (fun h => countId_neq_zero_of_mem_withDualInOther l l2 i h)
(fun h => ?_)
by_contra hn
have hn' := countId_of_not_mem_withDualInOther l l2 i hn
omega
lemma mem_withoutDual_iff_countId_eq_one (i : Fin l.length) :
i ∈ l.withoutDual ↔ l.countId (l.val.get i) = 1 := by
refine Iff.intro (fun h => ?_) (fun h => ?_)
· exact countId_of_not_mem_withDual l i (l.not_mem_withDual_of_mem_withoutDual i h)
· by_contra hn
have h : i ∈ l.withDual := by
simp [withoutDual] at hn
simpa using Option.ne_none_iff_isSome.mp hn
rw [mem_withDual_iff_countId_gt_one] at h
omega
lemma countId_eq_two_of_mem_withUniqueDual (i : Fin l.length) (h : i ∈ l.withUniqueDual) :
l.countId (l.val.get i) = 2 := by
rw [countId_get]
simp
let i' := (l.getDual? i).get (mem_withUniqueDual_isSome l i h)
have h1 : [i'] = (List.finRange l.length).filter (fun j => (l.AreDualInSelf i j)) := by
trans List.filter (fun j => (l.AreDualInSelf i j)) [i']
· simp [List.filter, i']
trans List.filter (fun j => (l.AreDualInSelf i j))
((List.finRange l.length).filter (fun j => j = i'))
· apply congrArg
rw [← filter_finRange l i']
apply List.filter_congr (fun j _ => ?_)
simpa using eq_comm
trans List.filter (fun j => j = i')
((List.finRange l.length).filter (fun j => (l.AreDualInSelf i j)))
· simp
apply List.filter_congr (fun j _ => ?_)
exact Bool.and_comm (decide (l.AreDualInSelf i j)) (decide (j = i'))
· simp
refine List.filter_congr (fun j _ => ?_)
simp
simp [withUniqueDual] at h
intro hj
have hj' := h.2 j hj
apply Option.some_injective
rw [hj']
simp [i']
rw [List.countP_eq_length_filter, ← h1]
simp
lemma mem_withUniqueDual_of_countId_eq_two (i : Fin l.length)
(h : l.countId (l.val.get i) = 2) : i ∈ l.withUniqueDual := by
have hw : i ∈ l.withDual := by
rw [mem_withDual_iff_countId_gt_one, h]
exact Nat.one_lt_two
simp [withUniqueDual]
apply And.intro ((mem_withDual_iff_isSome l i).mp hw)
intro j hj
rw [@countId_get] at h
simp [List.countP_eq_length_filter] at h
rw [List.length_eq_one] at h
obtain ⟨a, ha⟩ := h
have hj : j ∈ List.filter (fun j => decide (l.AreDualInSelf i j)) (List.finRange l.length) := by
simpa using hj
rw [ha] at hj
simp at hj
subst hj
have ht : (l.getDual? i).get ((mem_withDual_iff_isSome l i).mp hw) ∈
(List.finRange l.length).filter (fun j => decide (l.AreDualInSelf i j)) := by
simp
rw [ha] at ht
simp at ht
subst ht
simp
lemma mem_withUniqueDual_iff_countId_eq_two (i : Fin l.length) :
i ∈ l.withUniqueDual ↔ l.countId (l.val.get i) = 2 :=
Iff.intro (fun h => l.countId_eq_two_of_mem_withUniqueDual i h)
(fun h => l.mem_withUniqueDual_of_countId_eq_two i h)
lemma mem_withUniqueDualInOther_iff_countId_eq_one (i : Fin l.length) :
i ∈ l.withUniqueDualInOther l2 ↔ l.countId (l.val.get i) = 1 ∧ l2.countId (l.val.get i) = 1 := by
simp only [withUniqueDualInOther, Finset.mem_filter, Finset.mem_univ, true_and,
List.get_eq_getElem]
rw [mem_withDual_iff_countId_gt_one]
rw [mem_withDualInOther_iff_countId_neq_zero]
have hneq : l.countId (l.val.get i) ≠ 0 := by exact countId_index_neq_zero l i
end IndexList
end IndexNotation

View file

@ -0,0 +1,379 @@
/-
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.IndexList.Basic
/-!
# Indices which are dual in an index list
Given an list of indices we say two indices are dual if they have the same id.
For example the `0`, `2` and `3` index in `l₁ := ['ᵘ¹', 'ᵘ²', 'ᵤ₁', 'ᵘ¹']` are pairwise dual to
one another. The `1` (`'ᵘ²'`) index is not dual to any other index in the list.
We also define the notion of dual indices in different lists. For example,
the `1` index in `l₁` is dual to the `1` and the `4` indices in
`l₂ := ['ᵘ³', 'ᵘ²', 'ᵘ⁴', 'ᵤ₂']`.
-/
namespace IndexNotation
namespace IndexList
variable {X : Type} [IndexNotation X] [Fintype X] [DecidableEq X]
variable (l l2 l3 : IndexList X)
/-!
## Definitions
-/
/-- Two indices are dual if they are not equivalent, but have the same id. -/
def AreDualInSelf (i j : Fin l.length) : Prop :=
i ≠ j ∧ l.idMap i = l.idMap j
instance (i j : Fin l.length) : Decidable (l.AreDualInSelf i j) :=
instDecidableAnd
/-- Two indices in different `IndexLists` are dual to one another if they have the same `id`. -/
def AreDualInOther (i : Fin l.length) (j : Fin l2.length) :
Prop := l.idMap i = l2.idMap j
instance {l : IndexList X} {l2 : IndexList X} (i : Fin l.length) (j : Fin l2.length) :
Decidable (l.AreDualInOther l2 i j) := (l.idMap i).decEq (l2.idMap j)
/-- Given an `i`, if a dual exists in the same list,
outputs the first such dual, otherwise outputs `none`. -/
def getDual? (i : Fin l.length) : Option (Fin l.length) :=
Fin.find (fun j => l.AreDualInSelf i j)
/-- Given an `i`, if a dual exists in the other list,
outputs the first such dual, otherwise outputs `none`. -/
def getDualInOther? (i : Fin l.length) : Option (Fin l2.length) :=
Fin.find (fun j => l.AreDualInOther l2 i j)
/-- The finite set of indices of an index list which have a dual in that index list. -/
def withDual : Finset (Fin l.length) :=
Finset.filter (fun i => (l.getDual? i).isSome) Finset.univ
/-- The finite set of indices of an index list which do not have a dual. -/
def withoutDual : Finset (Fin l.length) :=
Finset.filter (fun i => (l.getDual? i).isNone) Finset.univ
/-- The finite set of indices of an index list which have a dual in another provided index list. -/
def withDualInOther : Finset (Fin l.length) :=
Finset.filter (fun i => (l.getDualInOther? l2 i).isSome) Finset.univ
/-- The finite set of indices of an index list which have a unique dual in that index list. -/
def withUniqueDual : Finset (Fin l.length) :=
Finset.filter (fun i => i ∈ l.withDual ∧
∀ j, l.AreDualInSelf i j → j = l.getDual? i) Finset.univ
/-- The finite set of indices of an index list which have a unique dual in another, provided, index
list. -/
def withUniqueDualInOther : Finset (Fin l.length) :=
Finset.filter (fun i => i ∉ l.withDual ∧ i ∈ l.withDualInOther l2
∧ (∀ j, l.AreDualInOther l2 i j → j = l.getDualInOther? l2 i)) Finset.univ
/-!
## Basic properties
-/
@[simp, nolint simpNF]
lemma mem_withDual_of_mem_withUniqueDual (i : Fin l.length) (h : i ∈ l.withUniqueDual) :
i ∈ l.withDual := by
simp only [withUniqueDual, Finset.mem_filter, Finset.mem_univ, true_and] at h
simpa using h.1
lemma mem_withDual_of_withUniqueDual (i : l.withUniqueDual) :
i.1 ∈ l.withDual :=
mem_withDual_of_mem_withUniqueDual l (↑i) i.2
lemma not_mem_withDual_of_withUniqueDualInOther (i : l.withUniqueDualInOther l2) :
i.1 ∉ l.withDual := by
have hi := i.2
simp only [withUniqueDualInOther, Finset.univ_eq_attach, Finset.mem_filter, Finset.mem_attach,
true_and] at hi
exact hi.2.1
lemma mem_withDualInOther_of_withUniqueDualInOther (i : l.withUniqueDualInOther l2) :
i.1 ∈ l.withDualInOther l2 := by
have hi := i.2
simp only [withUniqueDualInOther, Finset.univ_eq_attach, Finset.mem_filter, Finset.mem_attach,
true_and] at hi
exact hi.2.2.1
@[simp]
lemma withDual_isSome (i : l.withDual) : (l.getDual? i).isSome := by
simpa [withDual] using i.2
@[simp]
lemma mem_withDual_iff_isSome (i : Fin l.length) : i ∈ l.withDual ↔ (l.getDual? i).isSome := by
simp [withDual]
@[simp]
lemma mem_withUniqueDual_isSome (i : Fin l.length) (h : i ∈ l.withUniqueDual) :
(l.getDual? i).isSome := by
simpa [withDual] using mem_withDual_of_mem_withUniqueDual l i h
@[simp]
lemma mem_withInDualOther_iff_isSome (i : Fin l.length) :
i ∈ l.withDualInOther l2 ↔ (l.getDualInOther? l2 i).isSome := by
simp only [withDualInOther, getDualInOther?, Finset.mem_filter, Finset.mem_univ, true_and]
@[simp]
lemma mem_withUniqueDualInOther_isSome (i : Fin l.length) (hi : i ∈ l.withUniqueDualInOther l2) :
(l.getDualInOther? l2 i).isSome := by
simp only [withUniqueDualInOther, Finset.mem_filter, Finset.mem_univ, true_and] at hi
exact (mem_withInDualOther_iff_isSome l l2 i).mp hi.2.1
lemma not_mem_withDual_iff_isNone (i : Fin l.length) :
i ∉ l.withDual ↔ (l.getDual? i).isNone := by
simp only [mem_withDual_iff_isSome, Bool.not_eq_true, Option.not_isSome,
Option.isNone_iff_eq_none]
lemma mem_withDual_iff_exists : i ∈ l.withDual ↔ ∃ j, l.AreDualInSelf i j := by
simp [withDual, Finset.mem_filter, Finset.mem_univ, getDual?]
exact Fin.isSome_find_iff
lemma mem_withInDualOther_iff_exists :
i ∈ l.withDualInOther l2 ↔ ∃ (j : Fin l2.length), l.AreDualInOther l2 i j := by
simp [withDualInOther, Finset.mem_filter, Finset.mem_univ, getDualInOther?]
exact Fin.isSome_find_iff
lemma withDual_disjoint_withoutDual : Disjoint l.withDual l.withoutDual := by
rw [Finset.disjoint_iff_ne]
intro a ha b hb
by_contra hn
subst hn
simp_all only [withDual, Finset.mem_filter, Finset.mem_univ, true_and, withoutDual,
Option.isNone_iff_eq_none, Option.isSome_none, Bool.false_eq_true]
lemma not_mem_withDual_of_mem_withoutDual (i : Fin l.length) (h : i ∈ l.withoutDual) :
i ∉ l.withDual := by
have h1 := l.withDual_disjoint_withoutDual
exact Finset.disjoint_right.mp h1 h
/-!
## Are dual properties
-/
namespace AreDualInSelf
variable {l l2 : IndexList X} {i j : Fin l.length}
instance (i j : Fin l.length) : Decidable (l.AreDualInSelf i j) :=
instDecidableAnd
@[symm]
lemma symm (h : l.AreDualInSelf i j) : l.AreDualInSelf j i := by
simp only [AreDualInSelf] at h ⊢
exact ⟨h.1.symm, h.2.symm⟩
@[simp]
lemma self_false (i : Fin l.length) : ¬ l.AreDualInSelf i i := by
simp [AreDualInSelf]
@[simp]
lemma append_inl_inl : (l ++ l2).AreDualInSelf (appendEquiv (Sum.inl i)) (appendEquiv (Sum.inl j))
↔ l.AreDualInSelf i j := by
simp [AreDualInSelf]
@[simp]
lemma append_inr_inr (l l2 : IndexList X) (i j : Fin l2.length) :
(l ++ l2).AreDualInSelf (appendEquiv (Sum.inr i)) (appendEquiv (Sum.inr j))
↔ l2.AreDualInSelf i j := by
simp [AreDualInSelf]
@[simp]
lemma append_inl_inr (l l2 : IndexList X) (i : Fin l.length) (j : Fin l2.length) :
(l ++ l2).AreDualInSelf (appendEquiv (Sum.inl i)) (appendEquiv (Sum.inr j)) =
l.AreDualInOther l2 i j := by
simp [AreDualInSelf, AreDualInOther]
@[simp]
lemma append_inr_inl (l l2 : IndexList X) (i : Fin l2.length) (j : Fin l.length) :
(l ++ l2).AreDualInSelf (appendEquiv (Sum.inr i)) (appendEquiv (Sum.inl j)) =
l2.AreDualInOther l i j := by
simp [AreDualInSelf, AreDualInOther]
end AreDualInSelf
namespace AreDualInOther
variable {l l2 l3 : IndexList X} {i : Fin l.length} {j : Fin l2.length}
instance {l : IndexList X} {l2 : IndexList X} (i : Fin l.length) (j : Fin l2.length) :
Decidable (l.AreDualInOther l2 i j) := (l.idMap i).decEq (l2.idMap j)
@[symm]
lemma symm (h : l.AreDualInOther l2 i j) : l2.AreDualInOther l j i := by
rw [AreDualInOther] at h ⊢
exact h.symm
@[simp]
lemma append_of_inl (i : Fin l.length) (j : Fin l3.length) :
(l ++ l2).AreDualInOther l3 (appendEquiv (Sum.inl i)) j ↔ l.AreDualInOther l3 i j := by
simp [AreDualInOther]
@[simp]
lemma append_of_inr (i : Fin l2.length) (j : Fin l3.length) :
(l ++ l2).AreDualInOther l3 (appendEquiv (Sum.inr i)) j ↔ l2.AreDualInOther l3 i j := by
simp [AreDualInOther]
@[simp]
lemma of_append_inl (i : Fin l.length) (j : Fin l2.length) :
l.AreDualInOther (l2 ++ l3) i (appendEquiv (Sum.inl j)) ↔ l.AreDualInOther l2 i j := by
simp [AreDualInOther]
@[simp]
lemma of_append_inr (i : Fin l.length) (j : Fin l3.length) :
l.AreDualInOther (l2 ++ l3) i (appendEquiv (Sum.inr j)) ↔ l.AreDualInOther l3 i j := by
simp [AreDualInOther]
end AreDualInOther
/-!
## Basic properties of getDual?
-/
lemma getDual?_isSome_iff_exists (i : Fin l.length) :
(l.getDual? i).isSome ↔ ∃ j, l.AreDualInSelf i j := by
rw [getDual?, Fin.isSome_find_iff]
lemma getDual?_of_areDualInSelf (h : l.AreDualInSelf i j) :
l.getDual? j = i l.getDual? i = j l.getDual? j = l.getDual? i := by
have h3 : (l.getDual? i).isSome := by
simpa [getDual?, Fin.isSome_find_iff] using ⟨j, h⟩
obtain ⟨k, hk⟩ := Option.isSome_iff_exists.mp h3
rw [hk]
rw [getDual?, Fin.find_eq_some_iff] at hk
by_cases hik : i < k
· apply Or.inl
rw [getDual?, Fin.find_eq_some_iff]
apply And.intro h.symm
intro k' hk'
by_cases hik' : i = k'
· exact Fin.ge_of_eq (id (Eq.symm hik'))
· have hik'' : l.AreDualInSelf i k' := by
simp [AreDualInSelf, hik']
simp_all [AreDualInSelf]
have hk'' := hk.2 k' hik''
exact (lt_of_lt_of_le hik hk'').le
· by_cases hjk : j ≤ k
· apply Or.inr
apply Or.inl
have hj := hk.2 j h
simp only [Option.some.injEq]
exact Fin.le_antisymm hj hjk
· apply Or.inr
apply Or.inr
rw [getDual?, Fin.find_eq_some_iff]
apply And.intro
· simp_all [AreDualInSelf]
exact Fin.ne_of_gt hjk
intro k' hk'
by_cases hik' : i = k'
· subst hik'
exact Lean.Omega.Fin.le_of_not_lt hik
· have hik'' : l.AreDualInSelf i k' := by
simp [AreDualInSelf, hik']
simp_all [AreDualInSelf]
exact hk.2 k' hik''
@[simp]
lemma getDual?_neq_self (i : Fin l.length) : ¬ l.getDual? i = some i := by
intro h
simp [getDual?] at h
rw [Fin.find_eq_some_iff] at h
simp [AreDualInSelf] at h
@[simp]
lemma getDual?_get_neq_self (i : Fin l.length) (h : (l.getDual? i).isSome) :
¬ (l.getDual? i).get h = i := by
have h1 := l.getDual?_neq_self i
by_contra hn
have h' : l.getDual? i = some i := by
nth_rewrite 2 [← hn]
exact Option.eq_some_of_isSome h
exact h1 h'
@[simp]
lemma getDual?_get_id (i : Fin l.length) (h : (l.getDual? i).isSome) :
l.idMap ((l.getDual? i).get h) = l.idMap i := by
have h1 : l.getDual? i = some ((l.getDual? i).get h) := Option.eq_some_of_isSome h
nth_rewrite 1 [getDual?] at h1
rw [Fin.find_eq_some_iff] at h1
simp [AreDualInSelf] at h1
exact h1.1.2.symm
@[simp]
lemma getDual?_get_areDualInSelf (i : Fin l.length) (h : (l.getDual? i).isSome) :
l.AreDualInSelf ((l.getDual? i).get h) i := by
simp [AreDualInSelf]
@[simp]
lemma getDual?_areDualInSelf_get (i : Fin l.length) (h : (l.getDual? i).isSome) :
l.AreDualInSelf i ((l.getDual? i).get h) :=
AreDualInSelf.symm (getDual?_get_areDualInSelf l i h)
@[simp]
lemma getDual?_getDual?_get_isSome (i : Fin l.length) (h : (l.getDual? i).isSome) :
(l.getDual? ((l.getDual? i).get h)).isSome := by
rw [getDual?, Fin.isSome_find_iff]
exact ⟨i, getDual?_get_areDualInSelf l i h⟩
/-!
## Basic properties of getDualInOther?
-/
lemma getDualInOther?_isSome_iff_exists (i : Fin l.length) :
(l.getDualInOther? l2 i).isSome ↔ ∃ j, l.AreDualInOther l2 i j := by
rw [getDualInOther?, Fin.isSome_find_iff]
@[simp]
lemma getDualInOther?_id (i : Fin l.length) (h : (l.getDualInOther? l2 i).isSome) :
l2.idMap ((l.getDualInOther? l2 i).get h) = l.idMap i := by
have h1 : l.getDualInOther? l2 i = some ((l.getDualInOther? l2 i).get h) :=
Option.eq_some_of_isSome h
nth_rewrite 1 [getDualInOther?] at h1
rw [Fin.find_eq_some_iff] at h1
simp [AreDualInOther] at h1
exact h1.1.symm
@[simp]
lemma getDualInOther?_get_areDualInOther (i : Fin l.length) (h : (l.getDualInOther? l2 i).isSome) :
l2.AreDualInOther l ((l.getDualInOther? l2 i).get h) i := by
simp [AreDualInOther]
@[simp]
lemma getDualInOther?_areDualInOther_get (i : Fin l.length) (h : (l.getDualInOther? l2 i).isSome) :
l.AreDualInOther l2 i ((l.getDualInOther? l2 i).get h) :=
AreDualInOther.symm (getDualInOther?_get_areDualInOther l l2 i h)
@[simp]
lemma getDualInOther?_getDualInOther?_get_isSome (i : Fin l.length)
(h : (l.getDualInOther? l2 i).isSome) :
(l2.getDualInOther? l ((l.getDualInOther? l2 i).get h)).isSome := by
rw [getDualInOther?, Fin.isSome_find_iff]
exact ⟨i, getDualInOther?_get_areDualInOther l l2 i h⟩
@[simp]
lemma getDualInOther?_self_isSome (i : Fin l.length) :
(l.getDualInOther? l i).isSome := by
simp [getDualInOther?]
rw [@Fin.isSome_find_iff]
exact ⟨i, rfl⟩
end IndexList
end IndexNotation

View file

@ -997,8 +997,7 @@ lemma mem_withUniqueDual_iff_countId_eq_two (i : Fin l.length) :
(fun h => l.mem_withUniqueDual_of_countId_eq_two i h)
lemma getDual?_isSome_of_countId_eq_two {i : Fin l.length}
(h : l.countId (l.val.get i) = 2) :
(l.getDual? i).isSome := by
(h : l.countId (l.val.get i) = 2) : (l.getDual? i).isSome := by
rw [← l.mem_withUniqueDual_iff_countId_eq_two] at h
exact mem_withUniqueDual_isSome l i h