feat: Relationship between indices and countP

This commit is contained in:
jstoobysmith 2024-08-21 10:53:36 -04:00
parent 778373f135
commit d376632751
6 changed files with 355 additions and 152 deletions

View file

@ -5,6 +5,8 @@ Authors: Joseph Tooby-Smith
-/
import Mathlib.Data.Set.Finite
import Mathlib.Logic.Equiv.Fin
import Mathlib.Data.Finset.Sort
import Mathlib.Tactic.FinCases
/-!
# Index notation for a type
@ -392,6 +394,73 @@ lemma colorMap_sumELim (l1 l2 : IndexList X) :
end append
/-!
## countP on id
-/
lemma countP_id_neq_zero (i : Fin l.length) :
l.val.countP (fun J => (l.val.get i).id = J.id) ≠ 0 := by
rw [List.countP_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
/-! 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

@ -299,14 +299,6 @@ open IndexList TensorColor
instance : Coe (ColorIndexList 𝓒) (IndexList 𝓒.Color) := ⟨fun l => l.toIndexList⟩
/-! TODO: Define an induction principal on `ColorIndexList`. -/
/-- The `ColorIndexList` whose underlying list of indices is empty. -/
def empty : ColorIndexList 𝓒 where
val := ∅
unique_duals := rfl
dual_color := rfl
/-- 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) :=
@ -336,6 +328,28 @@ lemma orderEmbOfFin_univ (n m : ) (h : n = m) :
/-!
## Cons for `ColorIndexList`
-/
/-! TODO: Define `cons` for `ColorIndexList`. Will need conditions unlike for `IndexList`. -/
/-!
## Induction for `ColorIndexList`
-/
/-! TODO: Define an induction principal on `ColorIndexList`. -/
/-- The `ColorIndexList` whose underlying list of indices is empty. -/
def empty : ColorIndexList 𝓒 where
val := ∅
unique_duals := rfl
dual_color := rfl
/-!
## Contracting an `ColorIndexList`
-/

View file

@ -69,115 +69,16 @@ lemma withDual_union_withoutDual : l.withDual l.withoutDual = Finset.univ :=
· simp at h
simp [withoutDual, Finset.mem_filter, Finset.mem_univ, h]
lemma mem_withoutDual_iff_count :
(fun i => (i ∈ l.withoutDual : Bool)) =
(fun (i : Index X) => (l.val.countP (fun j => i.id = j.id) = 1 : Bool)) ∘ l.val.get := by
funext x
simp [withoutDual, getDual?]
rw [Fin.find_eq_none_iff]
simp [AreDualInSelf]
apply Iff.intro
· intro h
have h1 : ¬ l.val.Duplicate l.val[↑x] := by
by_contra hn
rw [List.duplicate_iff_exists_distinct_get] at hn
obtain ⟨i, j, h1, h2, h3⟩ := hn
have h4 := h i
have h5 := h j
simp [idMap] at h4 h5
by_cases hi : i = x
<;> by_cases hj : j = x
· subst hi hj
simp at h1
· subst hi
exact h5 (fun a => hj (id (Eq.symm a))) (congrArg Index.id h3)
· subst hj
exact h4 (fun a => hi (id (Eq.symm a))) (congrArg Index.id h2)
· exact h5 (fun a => hj (id (Eq.symm a))) (congrArg Index.id h3)
rw [List.duplicate_iff_two_le_count] at h1
simp at h1
by_cases hx : List.count l.val[↑x] l.val = 0
· rw [List.count_eq_zero] at hx
have hl : l.val[↑x] ∈ l.val := by
simp only [Fin.getElem_fin]
exact List.getElem_mem l.val (↑x) (Fin.val_lt_of_le x (le_refl l.length))
exact False.elim (h x (fun _ => hx hl) rfl)
have hln : List.count l.val[↑x] l.val = 1 := by
rw [@Nat.lt_succ] at h1
rw [@Nat.le_one_iff_eq_zero_or_eq_one] at h1
simp at hx
simpa [hx] using h1
rw [← hln, List.count]
refine (List.countP_congr ?_)
intro xt hxt
let xid := l.val.indexOf xt
have h2 := List.indexOf_lt_length.mpr hxt
have h3 : xt = l.val.get ⟨xid, h2⟩ := by
exact Eq.symm (List.indexOf_get h2)
simp only [decide_eq_true_eq, Fin.getElem_fin, beq_iff_eq]
by_cases hxtx : ⟨xid, h2⟩ = x
· rw [h3, hxtx]
simp only [List.get_eq_getElem]
refine Iff.intro (fun h' => False.elim (h x (fun _ => ?_) rfl)) (fun h' => ?_)
· exact h ⟨xid, h2⟩ (fun a => hxtx (id (Eq.symm a))) (by rw [h3] at h'; exact h')
· rw [h']
· intro h
intro i hxi
by_contra hn
by_cases hxs : x < i
· let ls := [l.val[x], l.val[i]]
have hsub : ls.Sublist l.val := by
rw [List.sublist_iff_exists_fin_orderEmbedding_get_eq]
let fs : Fin ls.length ↪o Fin l.val.length := {
toFun := ![x, i],
inj' := by
intro a b
fin_cases a <;>
fin_cases b
<;> simp [hxi]
exact fun a => hxi (id (Eq.symm a)),
map_rel_iff' := by
intro a b
fin_cases a <;>
fin_cases b
<;> simp [hxs]
omega}
use fs
intro a
fin_cases a <;> rfl
have h1 := List.Sublist.countP_le (fun (j : Index X) => decide (l.val[↑x].id = j.id)) hsub
simp only [Fin.getElem_fin, decide_True, List.countP_cons_of_pos, h, add_le_iff_nonpos_left,
nonpos_iff_eq_zero, ls] at h1
rw [@List.countP_eq_zero] at h1
simp at h1
exact h1 hn
have hxs' : i < x := by omega
let ls := [l.val[i], l.val[x]]
have hsub : ls.Sublist l.val := by
rw [List.sublist_iff_exists_fin_orderEmbedding_get_eq]
let fs : Fin ls.length ↪o Fin l.val.length := {
toFun := ![i, x],
inj' := by
intro a b
fin_cases a <;>
fin_cases b
<;> simp [hxi]
exact fun a => hxi (id (Eq.symm a)),
map_rel_iff' := by
intro a b
fin_cases a <;>
fin_cases b
<;> simp [hxs']
omega}
use fs
intro a
fin_cases a <;> rfl
have h1 := List.Sublist.countP_le (fun (j : Index X) => decide (l.val[↑x].id = j.id)) hsub
simp [h, ls, hn,] at h1
rw [List.countP_cons_of_pos] at h1
· simp at h1
simp [idMap] at hn
simp [hn]
lemma mem_withoutDual_iff_countP (i : Fin l.length) :
i ∈ l.withoutDual ↔ l.val.countP (fun j => (l.val.get i).id = j.id) = 1 := by
refine Iff.intro (fun h => ?_) (fun h => ?_)
· exact countP_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_countP] at h
omega
/-- An equivalence from `Fin l.withoutDual.card` to `l.withoutDual` determined by
the order on `l.withoutDual` inherted from `Fin`. -/
@ -194,41 +95,8 @@ lemma list_ofFn_withoutDualEquiv_eq_sort :
lemma withoutDual_sort_eq_filter : l.withoutDual.sort (fun i j => i ≤ j) =
(List.finRange l.length).filter (fun i => i ∈ l.withoutDual) := by
have h1 {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
rw [withoutDual]
rw [← h1]
rw [← filter_sort_comm]
simp only [Option.isNone_iff_eq_none, Finset.mem_filter, Finset.mem_univ, true_and]
apply congrArg
exact Fin.sort_univ l.length
@ -274,7 +142,9 @@ lemma contrIndexList_eq_contrIndexList' : l.contrIndexList = l.contrIndexList' :
let f1 : Index X → Bool := fun (i : Index X) => l.val.countP (fun j => i.id = j.id) = 1
let f2 : (Fin l.length) → Bool := fun i => i ∈ l.withoutDual
change List.filter f1 l.val = List.map l.val.get (List.filter f2 (List.finRange l.length))
have hf : f2 = f1 ∘ l.val.get := mem_withoutDual_iff_count l
have hf : f2 = f1 ∘ l.val.get := by
funext i
simp only [mem_withoutDual_iff_countP l, List.get_eq_getElem, Function.comp_apply, f2, f1]
rw [hf, ← List.filter_map]
apply congrArg
simp [length]

View file

@ -5,6 +5,7 @@ Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzTensor.IndexNotation.WithUniqueDual
import Mathlib.Algebra.Order.Ring.Nat
import Mathlib.Data.Finset.Sort
/-!
# withDuals equal to withUniqueDuals
@ -123,6 +124,78 @@ lemma withUnqiueDual_eq_withDual_of_empty (h : l.withDual = ∅) :
have hx' := x'.2
simp [h] at hx'
lemma withUniqueDual_eq_withDual_iff_sort_eq :
l.withUniqueDual = l.withDual ↔
l.withUniqueDual.sort (fun i j => i ≤ j) = l.withDual.sort (fun i j => i ≤ j) := by
refine Iff.intro (fun h => ?_) (fun h => ?_)
· rw [h]
· have h1 := congrArg Multiset.ofList h
rw [Finset.sort_eq, Finset.sort_eq] at h1
exact Eq.symm ((fun {α} {s t} => Finset.val_inj.mp) (id (Eq.symm h1)))
/-!
# withUniqueDual equal to withDual and count conditions.
-/
lemma withUniqueDual_eq_withDual_iff_countP :
l.withUniqueDual = l.withDual ↔
∀ i, l.val.countP (fun J => (l.val.get i).id = J.id) ≤ 2 := by
refine Iff.intro (fun h i => ?_) (fun h => ?_)
· by_cases hi : i ∈ l.withDual
· rw [← h] at hi
rw [mem_withUniqueDual_iff_countP] at hi
rw [hi]
· rw [mem_withDual_iff_countP] at hi
simp at hi
exact Nat.le_succ_of_le hi
· refine Finset.ext (fun i => ?_)
rw [mem_withUniqueDual_iff_countP, mem_withDual_iff_countP]
have hi := h i
omega
lemma withUniqueDual_eq_withDual_iff_countP_mem_le_two :
l.withUniqueDual = l.withDual ↔
∀ I (_ : I ∈ l.val), l.val.countP (fun J => I.id = J.id) ≤ 2 := by
rw [withUniqueDual_eq_withDual_iff_countP]
refine Iff.intro (fun h I hI => ?_) (fun h i => ?_)
· let i := l.val.indexOf I
have hi : i < l.length := List.indexOf_lt_length.mpr hI
have hIi : I = l.val.get ⟨i, hi⟩ := (List.indexOf_get hi).symm
rw [hIi]
exact h ⟨i, hi⟩
· exact h (l.val.get i) (List.getElem_mem l.val (↑i) i.isLt)
lemma withUniqueDual_eq_withDual_iff_all_countP_le_two :
l.withUniqueDual = l.withDual ↔
l.val.all (fun I => l.val.countP (fun J => I.id = J.id) ≤ 2) := by
rw [withUniqueDual_eq_withDual_iff_countP_mem_le_two]
simp only [List.all_eq_true, decide_eq_true_eq]
/-!
## Relationship with cons
-/
lemma withUniqueDual_eq_withDual_cons_iff (I : Index X) (hl : l.withUniqueDual = l.withDual) :
(l.cons I).withUniqueDual = (l.cons I).withDual
↔ l.val.countP (fun J => I.id = J.id) ≤ 1 := by
rw [withUniqueDual_eq_withDual_iff_all_countP_le_two]
simp
intro h I' hI'
by_cases hII' : I'.id = I.id
· rw [List.countP_cons_of_pos]
· rw [hII']
omega
· simpa using hII'
· rw [List.countP_cons_of_neg]
· rw [withUniqueDual_eq_withDual_iff_countP_mem_le_two] at hl
exact hl I' hI'
· simpa using hII'
/-!
## withUniqueDualInOther equal to withDualInOther append conditions

View file

@ -5,6 +5,7 @@ Authors: Joseph Tooby-Smith
-/
import HepLean.SpaceTime.LorentzTensor.IndexNotation.GetDual
import Mathlib.Algebra.Order.Ring.Nat
import Mathlib.Tactic.FinCases
/-!
# Indices with duals.
@ -72,6 +73,98 @@ lemma mem_withDual_iff_exists : i ∈ l.withDual ↔ ∃ j, l.AreDualInSelf i j
/-!
## Relationship between membership of withDual and countP on id.
-/
lemma countP_of_mem_withDual (i : Fin l.length) (h : i ∈ l.withDual) :
1 < l.val.countP (fun J => (l.val.get i).id = J.id) := by
rw [mem_withDual_iff_exists] at h
obtain ⟨j, hj⟩ := h
simp [AreDualInSelf, idMap] at hj
by_contra hn
have hn' := l.countP_id_neq_zero i
have hl : 2 ≤ l.val.countP (fun J => (l.val.get i).id = J.id) := by
by_cases hij : i < j
· have hsub : List.Sublist [l.val.get i, l.val.get j] l.val := by
rw [List.sublist_iff_exists_fin_orderEmbedding_get_eq]
refine ⟨⟨⟨![i, j], ?_⟩, ?_⟩, ?_⟩
· refine List.nodup_ofFn.mp ?_
simpa using Fin.ne_of_lt hij
· intro a b
fin_cases a, b
<;> simp [hij]
exact Fin.le_of_lt hij
· intro a
fin_cases a <;> rfl
simpa [hj.2] using List.Sublist.countP_le
(fun (j : Index X) => decide (l.val[i].id = j.id)) hsub
· have hij' : j < i := by omega
have hsub : List.Sublist [l.val.get j, l.val.get i] l.val := by
rw [List.sublist_iff_exists_fin_orderEmbedding_get_eq]
refine ⟨⟨⟨![j, i], ?_⟩, ?_⟩, ?_⟩
· refine List.nodup_ofFn.mp ?_
simpa using Fin.ne_of_lt hij'
· intro a b
fin_cases a, b
<;> simp [hij']
exact Fin.le_of_lt hij'
· intro a
fin_cases a <;> rfl
simpa [hj.2] using List.Sublist.countP_le
(fun (j : Index X) => decide (l.val[i].id = j.id)) hsub
omega
lemma countP_of_not_mem_withDual (i : Fin l.length)(h : i ∉ l.withDual) :
l.val.countP (fun J => (l.val.get i).id = J.id) = 1 := by
rw [mem_withDual_iff_exists] at h
simp [AreDualInSelf] at h
have h1 : ¬ l.val.Duplicate (l.val.get i) := by
by_contra hn
rw [List.duplicate_iff_exists_distinct_get] at hn
obtain ⟨k, j, h1, h2, h3⟩ := hn
by_cases hi : k = i
<;> by_cases hj : j = i
· subst hi hj
simp at h1
· subst hi
exact h j (fun a => hj (id (Eq.symm a))) (congrArg Index.id h3)
· subst hj
exact h k (fun a => hi (id (Eq.symm a))) (congrArg Index.id h2)
· exact h j (fun a => hj (id (Eq.symm a))) (congrArg Index.id h3)
rw [List.duplicate_iff_two_le_count] at h1
simp at h1
by_cases hx : List.count l.val[i] l.val = 0
· rw [List.count_eq_zero] at hx
refine False.elim (h i (fun _ => hx ?_) rfl)
exact List.getElem_mem l.val (↑i) (Fin.val_lt_of_le i (le_refl l.length))
· have hln : List.count l.val[i] l.val = 1 := by
rw [Nat.lt_succ, Nat.le_one_iff_eq_zero_or_eq_one] at h1
simp at hx
simpa [hx] using h1
rw [← hln, List.count]
refine (List.countP_congr (fun xt hxt => ?_))
let xid := l.val.indexOf xt
have h2 := List.indexOf_lt_length.mpr hxt
simp only [decide_eq_true_eq, Fin.getElem_fin, beq_iff_eq]
by_cases hxtx : ⟨xid, h2⟩ = i
· rw [(List.indexOf_get h2).symm, hxtx]
simp only [List.get_eq_getElem]
· refine Iff.intro (fun h' => False.elim (h i (fun _ => ?_) rfl)) (fun h' => ?_)
· exact h ⟨xid, h2⟩ (fun a => hxtx (id (Eq.symm a))) (by
rw [(List.indexOf_get h2).symm] at h'; exact h')
· rw [h']
rfl
lemma mem_withDual_iff_countP (i : Fin l.length) :
i ∈ l.withDual ↔ 1 < l.val.countP (fun J => (l.val.get i).id = J.id) := by
refine Iff.intro (fun h => countP_of_mem_withDual l i h) (fun h => ?_)
by_contra hn
have hn' := countP_of_not_mem_withDual l i hn
omega
/-!
## Basic properties of withDualInOther
-/

View file

@ -911,6 +911,90 @@ lemma getDualInOtherEquiv_cast {l1 l2 l1' l2' : IndexList X} (h : l1 = l1') (h2
subst h h2
rfl
/-!
## Membership of withUniqueDual and countP on id
-/
lemma finset_filter_id_mem_withUniqueDual (i : Fin l.length) (h : i ∈ l.withUniqueDual) :
Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ =
{i, (l.getDual? i).get (l.mem_withUniqueDual_isSome i h)} := by
refine Finset.ext (fun j => ?_)
simp
rw [← propext (eq_getDual?_get_of_withUniqueDual_iff l i j h)]
simp only [AreDualInSelf, ne_eq]
refine Iff.intro (fun h => ?_) (fun h=> ?_)
· simp_all only [and_true]
exact Or.symm (Decidable.not_or_of_imp fun h => h.symm)
· cases h with
| inl h =>
subst h
simp_all only
| inr h => simp_all only
lemma mem_withUniqueDual_of_finset_filter (i : Fin l.length) (h : i ∈ l.withDual)
(hf : Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ =
{i, (l.getDual? i).get ((mem_withDual_iff_isSome l i).mp h)}) :
i ∈ l.withUniqueDual := by
simp only [withUniqueDual, mem_withDual_iff_isSome, Finset.mem_filter, Finset.mem_univ, true_and]
apply And.intro
· simpa using h
· intro j hj
simp only [AreDualInSelf, ne_eq] at hj
have hj' : j ∈ Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ := by
simpa using hj.2
rw [hf] at hj'
simp at hj'
rcases hj' with hj' | hj'
· simp_all
· rw [hj']
simp
lemma mem__withUniqueDual_iff_finset_filter (i : Fin l.length) (h : i ∈ l.withDual) :
i ∈ l.withUniqueDual ↔ Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ =
{i, (l.getDual? i).get ((mem_withDual_iff_isSome l i).mp h)} :=
Iff.intro (fun h' => finset_filter_id_mem_withUniqueDual l i h')
(fun h' => mem_withUniqueDual_of_finset_filter l i h h')
/-! TODO: Move -/
lemma card_finset_self_dual (i : Fin l.length) (h : i ∈ l.withDual) :
({i, (l.getDual? i).get ((mem_withDual_iff_isSome l i).mp h)} : Finset (Fin l.length)).card = 2 := by
rw [Finset.card_eq_two]
use i, (l.getDual? i).get ((mem_withDual_iff_isSome l i).mp h)
simp
have h1 : l.AreDualInSelf i ((l.getDual? i).get ((mem_withDual_iff_isSome l i).mp h)) := by
simp
exact h1.1
lemma countP_of_mem_withUniqueDual (i : Fin l.length) (h : i ∈ l.withUniqueDual) :
l.val.countP (fun J => (l.val.get i).id = J.id) = 2 := by
rw [List.countP_eq_length_filter, filter_id_eq_sort]
simp only [List.length_map, Finset.length_sort]
erw [l.finset_filter_id_mem_withUniqueDual i h]
refine l.card_finset_self_dual i (mem_withDual_of_mem_withUniqueDual l i h)
lemma mem_withUniqueDual_of_countP (i : Fin l.length)
(h : l.val.countP (fun J => (l.val.get i).id = J.id) = 2) : i ∈ l.withUniqueDual := by
have hw : i ∈ l.withDual := by
rw [mem_withDual_iff_countP, h]
exact Nat.one_lt_two
rw [l.mem__withUniqueDual_iff_finset_filter i hw]
rw [List.countP_eq_length_filter, filter_id_eq_sort] at h
simp at h
have hsub : {i, (l.getDual? i).get ((mem_withDual_iff_isSome l i).mp hw)} ⊆
Finset.filter (fun j => l.idMap i = l.idMap j) Finset.univ := by
rw [Finset.insert_subset_iff]
simp
refine ((Finset.subset_iff_eq_of_card_le ?_).mp hsub).symm
erw [h]
rw [l.card_finset_self_dual i hw]
lemma mem_withUniqueDual_iff_countP (i : Fin l.length) :
i ∈ l.withUniqueDual ↔ l.val.countP (fun J => (l.val.get i).id = J.id) = 2 :=
Iff.intro (fun h => l.countP_of_mem_withUniqueDual i h)
(fun h => l.mem_withUniqueDual_of_countP i h)
end IndexList
end IndexNotation