/-
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.TensorIndex
import HepLean.SpaceTime.LorentzTensor.IndexNotation.IndexString
import HepLean.SpaceTime.LorentzTensor.EinsteinNotation.Basic
/-!

# Index notation for Einstein tensors


-/

instance : IndexNotation einsteinTensorColor.Color where
  charList := {'ᵢ'}
  notaEquiv :=
    ⟨fun _ => ⟨'ᵢ', Finset.mem_singleton.mpr rfl⟩,
    fun _ => Unit.unit,
    fun _ => rfl,
    by
      intro c
      have hc2 := c.2
      simp only [↓Char.isValue, Finset.mem_singleton] at hc2
      exact SetCoe.ext (id (Eq.symm hc2))⟩

namespace einsteinTensor

open einsteinTensorColor
open IndexNotation IndexString
open TensorStructure TensorIndex

variable {R : Type} [CommSemiring R] {n m : ℕ}

instance : IndexNotation (einsteinTensor R n).Color := instIndexNotationColorEinsteinTensorColor
instance : DecidableEq (einsteinTensor R n).Color := instDecidableEqColorEinsteinTensorColor


@[simp]
lemma indexNotation_eq_color : @einsteinTensor.instIndexNotationColor R _ n =
    instIndexNotationColorEinsteinTensorColor := by
  rfl

@[simp]
lemma decidableEq_eq_color : @einsteinTensor.instDecidableEqColor R _ n  =
    instDecidableEqColorEinsteinTensorColor := by
  rfl

@[simp]
lemma einsteinTensor_color : (einsteinTensor R n).Color = einsteinTensorColor.Color := by
  rfl

@[simp]
lemma toTensorColor_eq : (einsteinTensor R n).toTensorColor = einsteinTensorColor := by
  rfl


/-- The construction of a tensor index from a tensor and a string satisfying conditions
  which can be automatically checked. This is a modified version of
  `TensorStructure.TensorIndex.mkDualMap` specific to real Lorentz tensors. -/
noncomputable def fromIndexStringColor {R : Type} [CommSemiring R]  {cn : Fin n → einsteinTensorColor.Color}
    (T : (einsteinTensor R m).Tensor cn) (s : String)
    (hs : listCharIsIndexString einsteinTensorColor.Color s.toList = true)
    (hn : n = (toIndexList' s hs).length)
    (hD : (toIndexList' s hs).withDual = (toIndexList' s hs).withUniqueDual)
    (hC : IndexList.ColorCond.bool (toIndexList' s hs))
    (hd : TensorColor.ColorMap.DualMap.boolFin'
      (toIndexList' s hs).colorMap (cn ∘ Fin.cast hn.symm)) :
    (einsteinTensor R m).TensorIndex :=
  TensorStructure.TensorIndex.mkDualMap T ⟨(toIndexList' s hs), hD,
      IndexList.ColorCond.iff_bool.mpr hC⟩ hn
      (TensorColor.ColorMap.DualMap.boolFin'_DualMap hd)

@[simp]
lemma fromIndexStringColor_indexList {R : Type} [CommSemiring R] {cn : Fin n → einsteinTensorColor.Color}
    (T : (einsteinTensor R m).Tensor cn) (s : String)
    (hs : listCharIsIndexString einsteinTensorColor.Color s.toList = true)
    (hn : n = (toIndexList' s hs).length)
    (hD : (toIndexList' s hs).withDual = (toIndexList' s hs).withUniqueDual)
    (hC : IndexList.ColorCond.bool (toIndexList' s hs))
    (hd : TensorColor.ColorMap.DualMap.boolFin'
      (toIndexList' s hs).colorMap (cn ∘ Fin.cast hn.symm)) :
    (fromIndexStringColor T s hs hn hD hC hd).toIndexList = toIndexList' s hs := by
  rfl


/-- A tactic used to prove `boolFin` for real Lornetz tensors. -/
macro "dualMapTactic" : tactic =>
    `(tactic| {
    simp only [toTensorColor_eq]
    decide })


/-- Notation for the construction of a tensor index from a tensor and a string.
  Conditions are checked automatically. -/
notation:20 T "|" S:21 => fromIndexStringColor T S
  (by decide)
  (by decide) (by decide)
  (by decide)
  (by dualMapTactic)

/-- A tactics used to prove `colorPropBool` for real Lorentz tensors. -/
macro "prodTactic" : tactic =>
    `(tactic| {
    apply (ColorIndexList.AppendCond.iff_bool _ _).mpr
    change @ColorIndexList.AppendCond.bool einsteinTensorColor
      instIndexNotationColorEinsteinTensorColor instDecidableEqColorEinsteinTensorColor _ _
    simp only [prod_toIndexList, indexNotation_eq_color, fromIndexStringColor, mkDualMap,
      toTensorColor_eq, decidableEq_eq_color]
    decide})

lemma mem_fin_list (n : ℕ) (i : Fin n) : i ∈ Fin.list n := by
  have h1' : (Fin.list n)[i] = i := Fin.getElem_list _ _
  exact h1' ▸ List.getElem_mem _ _ _

instance (n : ℕ) (i : Fin n) : Decidable (i ∈ Fin.list n) :=
  isTrue (mem_fin_list n i)



/-- The product of Real Lorentz tensors. Conditions on indices are checked automatically. -/
notation:10 T "⊗ᵀ" S:11 => TensorIndex.prod T S (by prodTactic)
/-- An example showing the allowed constructions. -/
example (T : (einsteinTensor R n).Tensor ![Unit.unit, Unit.unit]) : True := by
  let _ := T|"ᵢ₂ᵢ₃"
  let _ := T|"ᵢ₁ᵢ₂" ⊗ᵀ T|"ᵢ₂ᵢ₁"
  let _ := T|"ᵢ₁ᵢ₂" ⊗ᵀ T|"ᵢ₂ᵢ₁" ⊗ᵀ T|"ᵢ₃ᵢ₄"
  exact trivial

end einsteinTensor
