SysF_PTS.lib

Require Import Lt Le List Compare_dec Plus Minus EqNat Bool Omega Program.Equality.
From Autosubst Require Export Autosubst.
Require Export Decidable.

Ltac atom_ren :=
(repeat
match goal with
| [H : ?T = ?S.[ren ?xi] |- _] => (destruct S; simpl in H; try discriminate H);[idtac]; try match goal with [H : T = T |- _] => clear H end
| [H : ?S.[ren ?xi] = ?T |- _] => (destruct S; simpl in H; try discriminate H);[idtac]; try match goal with [H : T = T |- _] => clear H
end
end); ainv.

Class Functor (F : Type -> Type) := {fmap {X Y} : (X -> Y) -> F X -> F Y}.
Infix "<\$>" := fmap (left associativity, at level 11).

Class Monad (m : Type -> Type) :=
{
bind {X Y} : m X -> (X -> m Y) -> m Y;
ret {X} : X -> m X
}.

Notation "'do' x <- a ; s" := (bind a (fun x => s)) (right associativity, at level 100).

Notation "'GET' x <- a ; P" := (match a with Some x => P | _ => False end) (right associativity, at level 100).

{ fmap X Y f a := do a' <- a; ret(f a') }.

{
bind X Y a f := match a with None => None | Some a' => f a' end;
ret := Some
}.

Lemma decide_refl {X Y} (a : X) (_ : Dec (a = a)) (s t : Y) : (if decide (a = a) then s else t) = s.
Proof. decide (a = a); congruence. Qed.

Ltac simpG := simpl in *; repeat match goal with
| [H : context[if decide (?s = ?s) then _ else _] |- _] => rewrite decide_refl in H
end.

Ltac ca := simpG; repeat match goal with
| [|- context[match ?s with _ => _ end]] => ( assert True as _; (destruct s eqn:?; simpG; try contradiction; try congruence; eauto)); [trivial | fail..]
| [H : context[match ?s with _ => _ end] |- _] => ( assert True as _; (destruct s eqn:?; simpG; try contradiction; try congruence; eauto)); [trivial | fail..]
end.

Ltac clean_goal := repeat
match goal with
[H : ?s = ?s |- _] => clear H
| [H : ?T |- _] => match T with _ /\ _ => idtac | (_,_) => idtac end; destruct H
end.

Ltac autodestr := repeat (clean_goal; try subst; simpl; match goal with [|- context[match ?s with _ => _ end]] =>
try match s with context[match _ with _ => _ end] => fail 2 end;
destruct s eqn:? end); try subst; simpl; trivial.

Ltac subst' := repeat progress match goal with [x : _ |- _] => subst x end.
Ltac clear_rec := first[subst | match goal with [H : _ = _ |- _] => clear H; subst end].

Tactic Notation "getH" open_constr(T) := match goal with [H : context[T] |- _] => exact H end.

Notation "\$\$( T )" := ltac:(getH T).
Notation "\$?" := ltac:(eauto; econstructor; try econstructor; now eauto) (only parsing).

Ltac aspec := repeat match goal with
| [H : _ |- _] => first[ specialize (H _ _ _ \$?) | specialize (H _ _ \$?) | specialize (H \$?) | specialize (H _ \$?) ] end.

Notation "(-1)" := (0 .: id).

Definition sum2bool {A B} (x : A + B) := if x then true else false.

Coercion sum2bool : sum >-> bool.

Definition comb {X Y} (bits : X -> bool) f g x : Y := if bits x then f x else g x.
Arguments comb {X Y} bits f g x/.

Lemma comb_cons {X} bits (sigma tau : var -> X) : comb bits sigma tau = (if bits 0 then sigma 0 else tau 0) .: comb ((+1) >>> bits) ((+1) >>> sigma) ((+1) >>> tau).
Proof. f_ext. intros [|]; reflexivity. Qed.

Lemma comb_comp {A B C} (bits : A -> bool) sigma tau (f : B -> C) : comb bits sigma tau >>> f = comb bits (sigma >>> f) (tau >>> f).
Proof. f_ext; intros. simpl. destruct (bits x); reflexivity. Qed.

Lemma upren_comb bits xi zeta b : upren (comb bits xi zeta) = comb (b .: bits) (upren xi) (upren zeta).
Proof. setoid_rewrite comb_cons at 2. destruct b; asimpl; unfold upren; now rewrite comb_comp. Qed.
(* Q-JK: before now: both S and (+1) appear in goal *)

Section SubstInstance.

Context {term : Type}.
Context {Ids_term : Ids term} {Rename_term : Rename term}
{Subst_term : Subst term} {SubstLemmas_term : SubstLemmas term}.

(* standard context lookup *)
Inductive atn: list term -> var -> term -> Prop :=
| Atn0 Delta A : atn (A :: Delta) 0 A
| AtnS Delta x A B :
atn Delta x B -> atn (A :: Delta) (S x) B.

Fixpoint get Gamma {struct Gamma} : var -> option term :=
match Gamma with
| nil => (fun n => None)
| s :: Gamma => Some s .: get Gamma
end.

Lemma get_atn Gamma n s : get Gamma n = Some s -> atn Gamma n s.
Proof.
revert n s. induction Gamma; intros n s E.
- inversion E.
- destruct n as [|n]; simpl in E.
+ inversion E; subst. constructor.
+ constructor; auto.
Qed.

Lemma atn_get Gamma n s : atn Gamma n s -> get Gamma n = Some s.
Proof. induction 1; intros; subst; simpl; now autorew. Qed.

Lemma mmap_atn {f : term -> term} {Gamma x A'} :
atn (mmap f Gamma) x A' -> exists A, A' = (f A) /\ atn Gamma x A.
Proof.
intros H. depind H.
- destruct Gamma; ainv. eexists. eauto using atn.
- destruct Gamma; try now ainv.
simpl in x.
inversion x.
destruct (IHatn _ _ _ \$\$(Gamma)) as [ B' [H_eq H_atn]].
exists B'. eauto using atn.
Qed.

Lemma atn_mmap {f : term -> term} {Gamma x A A'} :
atn Gamma x A -> A' = (f A) -> atn (mmap f Gamma) x A'.
Proof. induction 1; intros; subst; constructor; eauto. Qed.

Lemma mmap_get {f : term -> term} {Gamma x A'} :
get (mmap f Gamma) x = Some A' -> exists A, A' = (f A) /\ get Gamma x = Some A.
Proof.
intros H. apply get_atn in H. destruct (mmap_atn H) as [A [EA H']].
exists A; eauto using atn_get.
Qed.

Lemma get_mmap {f : term -> term} {Gamma x A A'} :
get Gamma x = Some A -> A' = (f A) -> get (mmap f Gamma) x = Some A'.
Proof. intros. apply atn_get. apply get_atn in H. eapply atn_mmap; eauto. Qed.

Lemma mmap_get_None {f : term -> term} {Gamma x} :
get (mmap f Gamma) x = None -> get Gamma x = None.
Proof.
intros H. case_eq (get Gamma x); trivial. intros t Et. exfalso.
eapply @get_mmap with (f:=f) in Et; eauto. congruence.
Qed.

Lemma get_mmap_None {f : term -> term} {Gamma x} :
get Gamma x = None -> get (mmap f Gamma) x = None.
Proof.
intros H. case_eq (get (mmap f Gamma) x); trivial. intros t Et. exfalso.
destruct (mmap_get Et) as [s [_ H']]. congruence.
Qed.

(* dependent context lookup *)
Inductive atnd: list term -> var -> term -> Prop :=
| Atnd0 Delta A A' :
A' = A.[ren(+1)] -> atnd (A :: Delta) 0 A'
| AtndS Delta x A B B' :
atnd Delta x B -> B' = B.[ren(+1)] -> atnd (A :: Delta) (S x) B'.

Fixpoint getD (Gamma : list term) n : option term :=
match Gamma with
| nil => fun n => None
| s :: Gamma => Some s.[ren(+1)] .: getD Gamma >>> fmap(subst(ren(+1)))
end n.
Arguments getD !Gamma/ n.

Lemma getD_atnd Gamma n s : getD Gamma n = Some s -> atnd Gamma n s.
Proof.
revert n s. induction Gamma; intros n s E.
- inversion E.
- destruct n as [|n].
+ simpl in E. inversion E; subst. now constructor.
+ simpl in E. case_eq (getD Gamma n); [intros t E'|intros E']; rewrite E' in E; inversion E; subst.
econstructor; eauto.
Qed.

Lemma atnd_getD Gamma n s : atnd Gamma n s -> getD Gamma n = Some s.
Proof. induction 1; intros; subst; simpl; now autorew. Qed.

(* Connecting the two notions *)
Lemma getD_get Gamma n : getD Gamma n = subst (ren(+S n)) <\$> (get Gamma n).
Proof.
revert Gamma; induction n; intros; destruct Gamma; simpl; autorew; trivial.
asimpl. autodestr. autosubst.
Qed.

Lemma getD_cons (s : term) (Gamma : list term) :
getD (s :: Gamma) = (Some s.[ren (+1)]) .: getD Gamma..[ren (+1)].
Proof.
f_ext. intros [|n]; trivial. rewrite getD_get.
replace ((Some s.[ren (+1)] .: getD Gamma..[ren (+1)]) (S n)) with (getD Gamma..[ren (+1)] n) by reflexivity.
repeat rewrite getD_get. asimpl.
case_eq (get Gamma n).
- intros t Et.
assert (E: get Gamma..[ren (+1)] n = Some t.[ren (+1)]) by (eapply get_mmap; eauto).
rewrite E; autosubst.
- intros E. rewrite get_mmap_None; trivial.
Qed.

End SubstInstance.

(* Generic context renamings *)

Section ContextRenamings.

Context {term : Type}.
Context {Ids_term : Ids term} {Rename_term : Rename term}
{Subst_term : Subst term} {SubstLemmas_term : SubstLemmas term}.

Definition cr xi Gamma Delta := forall n t, atnd Gamma n t -> atnd Delta (xi n) t.[ren xi].

Lemma cr_up t xi Gamma Delta : cr xi Gamma Delta -> cr (upren xi) (t :: Gamma) (t.[ren xi] :: Delta).
Proof. intros c [|] s l; inversion l; subst; econstructor; eauto; autosubst. Qed.

Lemma cr_shift Gamma t : cr (+1) Gamma (t :: Gamma).
Proof. intros n s l. asimpl. econstructor; eauto. Qed.

End ContextRenamings.

Section CtxBoolFun.

Context {term : Type}.
Context {Ids_term : Ids term} {Rename_term : Rename term}.

Definition bfr (xi : var -> var) delta gamma := forall n, gamma n = true -> delta (xi n) = true.

Lemma bfr_up b xi delta gamma : bfr xi delta gamma -> bfr (upren xi) (b .: delta) (b .: gamma).
Proof. intros H [|n] e; asimpl; eauto. Qed.

Lemma bfr_shift b gamma : bfr (+1) (b .: gamma) gamma.
Proof. intros n e. trivial. Qed.

Lemma bfr_ushift gamma : bfr (-1) gamma (false .: gamma).
Proof. intros [|n]; asimpl; trivial. discriminate. Qed.

End CtxBoolFun.

Section Coincidence.

Context {term : Type}.
Context {Ids_term : Ids term} {Rename_term : Rename term}
{Subst_term : Subst term} {SubstLemmas_term : SubstLemmas term}.

Definition subst_coinc (gamma : var -> bool) (sigma tau : var -> term) := forall n, gamma n = true -> sigma n = tau n.

Lemma subst_coinc_id gamma sigma : subst_coinc gamma sigma sigma.
Proof. now intros n. Qed.

Lemma subst_coinc_up b gamma sigma tau : subst_coinc gamma sigma tau -> subst_coinc (b .: gamma) (up sigma) (up tau).
Proof. intros H [|n] A; asimpl in *; trivial. now rewrite H. Qed.

(* Lemma ren_coinc_hd_f b gamma xi zeta : b = false -> subst_coinc gamma (ren xi) tau -> subst_coinc (b .: gamma) (ren (x .: xi)) (ren (z .: zeta)). *)
(* Proof. intros E H |n A; asimpl in *; try congruence. now apply H. Qed. *)

Lemma subst_coinc_hd_f b gamma sigma tau : b = false -> subst_coinc gamma ((+1) >>> sigma) ((+1) >>> tau) -> subst_coinc (b .: gamma) sigma tau.
Proof. intros E H [|n] A; asimpl in *; try congruence. now apply (H n). Qed.

End Coincidence.

Section CoincidenceHSubst.

Context {type : Type}.
Context {Ids_type : Ids type} {Rename_type : Rename type}
{Subst_type : Subst type} {SubstLemmas_type : SubstLemmas type}.

Context {term : Type}.
Context {Ids_term : Ids term} {Rename_term : Rename term}
{Subst_term : Subst term} {SubstLemmas_term : SubstLemmas term}
{HSubst_term : HSubst type term} {HSubstLemmas_term : HSubstLemmas type term}.

Lemma subst_coinc_hcomp gamma sigma tau rho : subst_coinc gamma sigma tau -> subst_coinc gamma (sigma >>| rho) (tau >>| rho).
Proof. intros H n E. asimpl. f_equal. eauto. Qed.

End CoincidenceHSubst.