Require Import List Lia.
Import ListNotations.
Require Import Undecidability.SystemF.SysF Undecidability.SystemF.Autosubst.syntax Undecidability.SystemF.Autosubst.unscoped.
Import UnscopedNotations.
Require Import Undecidability.SystemF.Util.Facts Undecidability.SystemF.Util.poly_type_facts.
Require Import ssreflect ssrbool ssrfun.
Set Default Goal Selector "!".
Fixpoint allfv_pure_term (p: nat -> Prop) (M: pure_term) :=
match M with
| pure_var x => p x
| pure_app M N => allfv_pure_term p M /\ allfv_pure_term p N
| pure_abs M => allfv_pure_term (scons True p) M
end.
Lemma allfv_pure_term_impl {p1 p2: nat -> Prop} {M}:
(forall x, p1 x -> p2 x) -> allfv_pure_term p1 M -> allfv_pure_term p2 M.
Proof.
elim: M p1 p2.
- move=> >. by apply.
- by move=> ? IH1 ? IH2 > /= /copy [/IH1 {}IH1 /IH2 {}IH2] [/IH1 ? /IH2 ?].
- move=> > IH > H /=. apply: IH. by case.
Qed.
Lemma allfv_pure_term_ren_pure_term {p ξ M} :
allfv_pure_term p (ren_pure_term ξ M) <-> allfv_pure_term (ξ >> p) M.
Proof.
elim: M ξ p.
- done.
- move=> ? IH1 ? IH2 > /=. by rewrite IH1 IH2.
- move=> ? IH > /=. rewrite IH. constructor; apply: allfv_pure_term_impl; by case.
Qed.
Lemma allfv_pure_term_TrueI {p: nat -> Prop} {M} : (forall x, p x) -> allfv_pure_term p M.
Proof.
move=> Hp. elim: M.
- move=> > /=. by apply: Hp.
- by move=> ? + ? + /=.
- move=> ? /=. apply: allfv_pure_term_impl. case; first done.
move=> *. by apply: Hp.
Qed.
Lemma ren_pure_term_id {M} : ren_pure_term id M = M.
Proof.
elim: M.
- done.
- move=> /=. congruence.
- move=> /=. rewrite /upRen_pure_term_pure_term.
move=> > ?. under extRen_pure_term => ? do rewrite up_ren_id. by congruence.
Qed.
Lemma ren_pure_term_id' {ξ M} : (forall x, ξ x = x) -> ren_pure_term ξ M = M.
Proof. move=> ?. rewrite -[RHS]ren_pure_term_id. by apply: extRen_pure_term. Qed.
Fixpoint pure_var_bound (M: pure_term) :=
match M with
| pure_var x => 1 + x
| pure_app M N => 1 + pure_var_bound M + pure_var_bound N
| pure_abs M => 1 + pure_var_bound M
end.
Lemma pure_var_boundP M : allfv_pure_term (gt (pure_var_bound M)) M.
Proof.
elim: M.
- move=> /=. by lia.
- move=> ? IH1 ? IH2 /=. constructor; [move: IH1 | move: IH2]; apply: allfv_pure_term_impl; by lia.
- move=> ? /=. apply: allfv_pure_term_impl. case; first done. move=> /=. by lia.
Qed.