Library AlphaEquality

Require Export Swap.
Set Implicit Arguments.

Section GramVC.
Variable G : CFGV.
Variable vc : VarSym G.

Notation vcDeq := (DeqVtype vc).


CatchFileBetweenTagsAbsStart

Notation vcType := (vType vc).
Inductive Abstraction : Type :=
| termAbs: {gs : GSym G},
    list vcTypeTerm gsAbstraction
| patAbs: {gs : GSym G},
    list vcTypePattern gsAbstraction.

CatchFileBetweenTagsAbsEnd
CatchFileBetweenTagsMakeAbsStart

Fixpoint MakeAbstractions {lgs} (m : Mixture lgs)
 (llB : list (list (vType vc))): list Abstraction :=
match m with
| mnil[]
| mtcons _ _ h tl⇒ (termAbs (lhead llB) h
                      ::(MakeAbstractions tl (tail llB)))
| mpcons _ _ h tl⇒ (patAbs (lhead llB) h
                      ::(MakeAbstractions tl (tail llB)))
end.

CatchFileBetweenTagsMakeAbsEnd

Definition MakeAbstractionsTNodeAux
    (lln: list (list nat))
    (mp : MixtureParam)
    (m :Mixture mp)
      : list Abstraction
:= MakeAbstractions m (lBoundVars vc lln m).

Definition MakeAbstractionsTNode (p: TermProd G)
    (m :Mixture (tpRhsAugIsPat p)) : list Abstraction
:= MakeAbstractionsTNodeAux (bndngPatIndices p) m.

there are no internal bindings within patterns
Definition MakeAbstractionsPNode
    {lgs: MixtureParam}
    (m: Mixture lgs)
     : list Abstraction
:= MakeAbstractions m [].

Definition swapAbs
           (a : Abstraction)
           (sw : Swapping vc)
    : Abstraction :=
match a with
| termAbs _ lbv ttermAbs (swapLVar sw lbv) (tSwap t sw)
| patAbs _ lbv tpatAbs (swapLVar sw lbv) (pSwap t sw)
end.

Definition swapLAbs
           (la : list Abstraction)
           (sw : Swapping vc)
    : list Abstraction :=
map (fun xswapAbs x sw) la.

Lemma swapBndngVarsCommute:
( (s : GSym G) (nt : Term s), True)
×
( (s : GSym G) (pt : Pattern s) (sw : Swapping vc),
    swapLVar sw (pBndngVars vc pt) = pBndngVars vc (pSwap pt sw)
)
×
( (l : list (bool # GSym G)) (m : Mixture l)
    (sw : Swapping vc)
    (nn : nat),
    swapLVar sw (getBVarsNth vc m nn) = @getBVarsNth
                            _ vc _ (mSwap m sw) nn
).
Proof.
 GInduction; allsimpl; introns Hyp; intros; cpx; [ | | | ].
- Case "pvleaf". rewrite DeqSym. symmetry.
  rewrite DeqSym. destruct_head_match;
  subst; auto.
- Case "pnode". simpl. simpl pBndngVars.
  rewrite mBndngVarsAsNth.
  rewrite mBndngVarsAsNth.
  autorewrite with fast.
  unfold swapLVar. unfold swapLVar in Hyp.
  rw map_flat_map.
  apply eq_flat_maps.
  intros nn Hin.
  unfold compose. trivial.
- simpl. destruct nn; auto.
- simpl. destruct nn; auto.
Qed.

Lemma swapLBoundVarsCommute :
 (l : MixtureParam) (m : Mixture l)
 (sw: Swapping vc)
 (la: list (list nat)),
 (swapLLVar sw) (lBoundVars vc la m)
=
lBoundVars vc la
 (mSwap m sw).
Proof.
  intros. unfold lBoundVars.
  unfold swapLLVar, swapLVar.
  rw map_map.
  apply eq_maps.
  intros n Hin.
  unfold compose.
  rw map_flat_map.
  apply eq_flat_maps.
  intros nn Hinn.
  clear dependent n.
  clear dependent la.
  unfold compose.
  pose proof swapBndngVarsCommute as XX.
  unfold swapLVar in XX.
  exrepnd.
  cpx.
Qed.

Lemma MakeLAbsSwapCommute:
(mp : MixtureParam) (sw : Swapping vc) (m : Mixture mp)
  (lbv : list (list vcType)),
swapLAbs (MakeAbstractions m lbv) sw =
MakeAbstractions (mSwap m sw) (swapLLVar sw lbv).
  intros np sw m.
  induction m; destruct lbv;
     allsimpl;auto;
  try(f_equal; auto; fail);[|];
  specialize (IHm []); allsimpl;
  f_equal; cpx.
Qed.

Lemma MakeAbsTNodeCommute:
    (p: TermProd G)
    (m :Mixture (tpRhsAugIsPat p))
    (sw: Swapping vc),
swapLAbs (MakeAbstractions m (lBoundVars vc (bndngPatIndices p) m)) sw =
MakeAbstractions (mSwap m sw)
  (lBoundVars vc (bndngPatIndices p) (mSwap m sw)).
Proof.
  intros.
  rw <- swapLBoundVarsCommute.
  apply MakeLAbsSwapCommute.
Qed.

Lemma MakeAbsPNodeCommute:
  (p: PatProd G)
  (m : Mixture (map (fun x : GSym G(true, x)) (ppRhsSym p)))
  (sw: Swapping vc),
swapLAbs (MakeAbstractions m []) sw
   = MakeAbstractions (mSwap m sw) [].
Proof.
  intros. unfold MakeAbstractionsPNode.
  apply MakeLAbsSwapCommute.
Qed.




CatchFileBetweenTagsAlphaStart

Notation zip := (combine).
Inductive tAlphaEq: {gs : (GSym G)},
      (Term gs) → (Term gs) → Type :=
| alt: T t, tAlphaEq (tleaf T t) (tleaf T t)
| alv: V v, tAlphaEq (vleaf V v) (vleaf V v)
| alnode: (p: TermProd G)
   (ma mb : Mixture (tpRhsAugIsPat p)),
   lAlphaEqAbs (MakeAbstractions ma (allBndngVars vc p ma))
               (MakeAbstractions mb (allBndngVars vc p mb))
   → tAlphaEq (tnode p ma) (tnode p mb)

with pAlphaEq:
    {gs : (GSym G)},
      (Pattern gs) → (Pattern gs) → Type :=
| alpt: T t, pAlphaEq (ptleaf T t) (ptleaf T t)
| alpvar: vcc vara varb, pAlphaEq (pvleaf vcc vara)
                                         (pvleaf vcc varb)
| alembed: p nta ntb,
    tAlphaEq nta ntbpAlphaEq (embed p nta) (embed p ntb)
| alpnode:
     (p: PatProd G)
    (ma mb : Mixture (map (fun x(true,x)) (ppRhsSym p))),
    lAlphaEqAbs (MakeAbstractions ma [])
                 (MakeAbstractions mb [])
    → pAlphaEq (pnode p ma) (pnode p mb)

with AlphaEqAbs: AbstractionAbstractionType :=
| alAbT : {gs : GSym G}
    (lbva lbvb lbnew : list vcType)
    (tma tmb : Term gs),
    let swapa := zip lbva lbnew in
    let swapb := zip lbvb lbnew in
    length lbva = length lbnew
    → length lbvb = length lbnew
    → tFresh lbnew [tma,tmb]
    → disjoint (lbva ++ lbvb) lbnew
    → tAlphaEq (tSwap tma swapa) (tSwap tmb swapb)
    → AlphaEqAbs (termAbs lbva tma) (termAbs lbvb tmb)
| alAbP : {gs : GSym G}
    (lbva lbvb lbnew : list vcType)
    (tma tmb : Pattern gs),
    let swapa := zip lbva lbnew in
    let swapb := zip lbvb lbnew in
    length lbva = length lbnew
    → length lbvb = length lbnew
    → pFresh lbnew [tma,tmb]
    → disjoint (lbva ++ lbvb) lbnew
    → pAlphaEq (pSwap tma swapa) (pSwap tmb swapb)
    → AlphaEqAbs (patAbs lbva tma) (patAbs lbvb tmb)

with lAlphaEqAbs :
  list Abstractionlist AbstractionType :=
| lAlAbsNil : lAlphaEqAbs [] []
| lAlAbsCons : (ha hb: Abstraction)
            (la lb: list Abstraction),
            AlphaEqAbs ha hb
            → lAlphaEqAbs la lb
            → lAlphaEqAbs (ha::la) (hb::lb).

CatchFileBetweenTagsAlphaEnd

Scheme tAlphaEqMut := Minimality for tAlphaEq Sort Type
with pAlphaEqMut := Minimality for pAlphaEq Sort Type
with alphaEqAbsMut := Minimality for AlphaEqAbs Sort Type
with lAlphaEqAbsMut := Minimality for lAlphaEqAbs Sort Type.

again, just renaming variables to more intuitive ones and putting all 4 parts in 1 lemma, so that the user gets all 4 proofs in 1 shot. Usually even to prove, the other onese have to be proved anyways
Lemma GAlphaInd:
(P : gs : GSym G, Term gsTerm gs[univ])
         (PP : gs : GSym G, Pattern gsPattern gs[univ])
         (PA : AbstractionAbstraction[univ])
         (PLA : list Abstractionlist Abstraction[univ]),
       ( (T : Terminal G) (t : tSemType G T),
        P (gsymT T) (tleaf T t) (tleaf T t)) →
       ( (V : VarSym G) (v : vType V),
        P (gsymTN (vSubstType G V)) (vleaf V v) (vleaf V v)) →
       ( (p : TermProd G) (ma mb : Mixture (tpRhsAugIsPat p)),
        lAlphaEqAbs (MakeAbstractions ma (allBndngVars vc p ma))
              (MakeAbstractions mb (allBndngVars vc p mb)) →
        PLA (MakeAbstractions ma (allBndngVars vc p ma))
            (MakeAbstractions mb (allBndngVars vc p mb)) →
        P (gsymTN (tpLhs G p)) (tnode p ma) (tnode p mb)) →
       ( (T : Terminal G) (t : tSemType G T),
        PP (gsymT T) (ptleaf T t) (ptleaf T t)) →
       ( (vcc : VarSym G) (vara varb : vType vcc),
        PP (gsymV vcc) (pvleaf vcc vara) (pvleaf vcc varb)) →
       ( (p : EmbedProd G) (nta ntb : Term (gsymTN (epRhs G p))),
        tAlphaEq nta ntb
        P (gsymTN (epRhs G p)) nta ntb
        PP (gsymPN (epLhs G p)) (embed p nta) (embed p ntb)) →
       ( (p : PatProd G)
          (ma mb : Mixture (map (fun x : GSym G(true, x)) (ppRhsSym p))),
        lAlphaEqAbs (MakeAbstractions ma []) (MakeAbstractions mb []) →
        PLA (MakeAbstractions ma []) (MakeAbstractions mb []) →
        PP (gsymPN (ppLhs G p)) (pnode p ma) (pnode p mb)) →
       ( (gs : GSym G) (lbva lbvb lbnew : list vcType)
          (tma tmb : Term gs),
        let swapa := combine lbva lbnew in
        let swapb := combine lbvb lbnew in
        length lbva = length lbnew
        length lbvb = length lbnew
        tFresh lbnew [tma, tmb]
        disjoint (lbva ++ lbvb) lbnew
        tAlphaEq (tSwap tma swapa) (tSwap tmb swapb) →
        P gs (tSwap tma swapa) (tSwap tmb swapb) →
        PA (termAbs lbva tma) (termAbs lbvb tmb)) →
       ( (gs : GSym G) (lbva lbvb lbnew : list vcType)
          (tma tmb : Pattern gs),
        let swapa := combine lbva lbnew in
        let swapb := combine lbvb lbnew in
        length lbva = length lbnew
        length lbvb = length lbnew
        pFresh lbnew [tma, tmb]
        disjoint (lbva ++ lbvb) lbnew
        pAlphaEq (pSwap tma swapa) (pSwap tmb swapb) →
        PP gs (pSwap tma swapa) (pSwap tmb swapb) →
        PA (patAbs lbva tma) (patAbs lbvb tmb)) →
       PLA [] []
       ( (ha hb : Abstraction) (la lb : list Abstraction),
        AlphaEqAbs ha hb
        PA ha hblAlphaEqAbs la lbPLA la lbPLA (ha :: la) (hb :: lb))
        →
(( (gs : GSym G) (ta tb : Term gs), tAlphaEq ta tbP gs ta tb)
 *( (gs : GSym G) (pa pb : Pattern gs),
      pAlphaEq pa pbPP gs pa pb)
 *( aa ab : Abstraction, AlphaEqAbs aa abPA aa ab)
 *( la lb : list Abstraction, lAlphaEqAbs la lbPLA la lb)
).
Proof.
intros. dands.
- eapply tAlphaEqMut; eauto.
- eapply pAlphaEqMut; eauto.
- eapply alphaEqAbsMut; eauto.
- eapply lAlphaEqAbsMut; eauto.
Defined.


Definition mAlphaEq
   {mp : MixtureParam}
   (ma mb : Mixture mp)
   (lln : list (list nat)) :=
lAlphaEqAbs
  (MakeAbstractionsTNodeAux lln ma)
  (MakeAbstractionsTNodeAux lln mb).

End GramVC.

Ltac GAlphaInd :=
  apply GAlphaInd ; [
                        Case "tleaf"
                      | Case "vleaf"
                      | Case "tnode"
                      | Case "ptleaf"
                      | Case "pvleaf"
                      | Case "pembed"
                      | Case "pnode"
                      | Case "termAbs"
                      | Case "patAbs"
                      | Case "laNil"
                      | Case "laCons"
].

Definition tAlphaEqual {G : CFGV} {gs : GSym G} (ta tb : Term gs):=
(vc: VarSym G), tAlphaEq vc ta tb.