From Stdlib Require Import List Bool Arith Lia PeanoNat. Import ListNotations. Definition atom := nat. Inductive ntrm : Type := | NVar : atom -> ntrm | NApp : ntrm -> ntrm -> ntrm | NLam : atom -> ntrm -> ntrm | NESub : ntrm -> atom -> ntrm -> ntrm | NMVar : atom -> list atom -> ntrm. Fixpoint nfv (t : ntrm) : list atom := match t with | NVar x => [x] | NApp a b => nfv a ++ nfv b | NLam x a => filter (fun y => negb (Nat.eqb y x)) (nfv a) | NESub a x b => filter (fun y => negb (Nat.eqb y x)) (nfv a) ++ nfv b | NMVar _ d => d end. Definition isubst_meta (X : atom) (d : list atom) (x : atom) (v : ntrm) : ntrm := if existsb (Nat.eqb x) d then NESub (NMVar X d) x v else NMVar X d. Lemma isubst_meta_in : forall X d x v, In x d -> isubst_meta X d x v = NESub (NMVar X d) x v. Proof. intros X d x v H. unfold isubst_meta. destruct (existsb (Nat.eqb x) d) eqn:E; [reflexivity |]. assert (Hex : existsb (Nat.eqb x) d = true) by (apply existsb_exists; exists x; split; [exact H | apply Nat.eqb_refl]). rewrite Hex in E. discriminate E. Qed. Lemma isubst_meta_notin : forall X d x v, ~ In x d -> isubst_meta X d x v = NMVar X d. Proof. intros X d x v H. unfold isubst_meta. destruct (existsb (Nat.eqb x) d) eqn:E; [| reflexivity]. exfalso. apply existsb_exists in E. destruct E as [y [Hy HE]]. apply Nat.eqb_eq in HE. subst y. apply H. exact Hy. Qed. Inductive nctx : Type := | nHole : nctx | nAppL : nctx -> ntrm -> nctx | nAppR : ntrm -> nctx -> nctx | nLam : atom -> nctx -> nctx | nESubL : nctx -> atom -> ntrm -> nctx | nESubR : ntrm -> atom -> nctx -> nctx. Fixpoint nplug (C : nctx) (t : ntrm) : ntrm := match C with | nHole => t | nAppL C1 u => NApp (nplug C1 t) u | nAppR u C1 => NApp u (nplug C1 t) | nLam x C1 => NLam x (nplug C1 t) | nESubL C1 x u => NESub (nplug C1 t) x u | nESubR t1 x C1 => NESub t1 x (nplug C1 t) end. Fixpoint is_subst_chain (C : nctx) : bool := match C with | nHole => true | nESubL C1 _ _ => is_subst_chain C1 | _ => false end. Inductive Es : ntrm -> ntrm -> Prop := | Es_refl : forall t, Es t t | Es_sym : forall t u, Es t u -> Es u t | Es_trans : forall t u v, Es t u -> Es u v -> Es t v | Es_C : forall t x u y v, y <> x -> ~ In y (nfv u) -> ~ In x (nfv v) -> Es (NESub (NESub t x u) y v) (NESub (NESub t y v) x u) | Es_ctx : forall C t t', Es t t' -> Es (nplug C t) (nplug C t'). Fixpoint cbinders (C : nctx) : list atom := match C with | nHole => [] | nAppL C1 _ => cbinders C1 | nAppR _ C1 => cbinders C1 | nLam x C1 => x :: cbinders C1 | nESubL C1 _ _ => cbinders C1 | nESubR _ _ C1 => cbinders C1 end. Definition cavoid (C : nctx) (phi : list atom) : bool := forallb (fun y => negb (existsb (Nat.eqb y) phi)) (cbinders C). Inductive nred : ntrm -> ntrm -> Prop := | nred_B : forall t x u, nred (NApp (NLam x t) u) (NESub t x u) | nred_Gc : forall t x u, ~ In x (nfv t) -> nred (NESub t x u) t | nred_RX : forall C X d x u phi, In x d -> In x phi -> (forall y, In y (nfv u) -> In y phi) -> is_subst_chain C = false -> nred (NESub (nplug C (NMVar X d)) x u) (NESub (nplug C (NESub (NMVar X d) x u)) x u) | nred_R : forall C x u phi, In x phi -> (forall y, In y (nfv u) -> In y phi) -> cavoid C phi = true -> nred (NESub (nplug C (NVar x)) x u) (NESub (nplug C u) x u) | nred_ctx : forall C t t', nred t t' -> nred (nplug C t) (nplug C t'). Lemma eqC_in_Es : forall t x u y v, y <> x -> ~ In y (nfv u) -> ~ In x (nfv v) -> Es (NESub (NESub t x u) y v) (NESub (NESub t y v) x u). Proof. intros. apply Es_C; assumption. Qed. Lemma Es_ctx_any : forall C t t', Es t t' -> Es (nplug C t) (nplug C t'). Proof. intros. apply Es_ctx. exact H. Qed. Lemma nred_R_intro : forall C x u phi, In x phi -> (forall y, In y (nfv u) -> In y phi) -> cavoid C phi = true -> nred (NESub (nplug C (NVar x)) x u) (NESub (nplug C u) x u). Proof. intros C x u phi Hx Hu Hc. apply nred_R with (phi := phi). - exact Hx. - exact Hu. - exact Hc. Qed. Lemma Es_refl_any : forall t, Es t t. Proof. intros. apply Es_refl. Qed. Lemma Es_sym_any : forall t u, Es t u -> Es u t. Proof. intros. apply Es_sym. exact H. Qed. Lemma Es_trans_any : forall t u v, Es t u -> Es u v -> Es t v. Proof. intros. apply Es_trans with (u := u); assumption. Qed. Print Assumptions isubst_meta_in. Print Assumptions isubst_meta_notin. Print Assumptions Es_ctx_any. Print Assumptions nred_R_intro. Print Assumptions eqC_in_Es. Print Assumptions Es_refl_any. Print Assumptions Es_sym_any. Print Assumptions Es_trans_any. Lemma in_filter_neq : forall y x l, In y (filter (fun z => negb (Nat.eqb z x)) l) -> In y l /\ y <> x. Proof. intros y x l H. apply filter_In in H. destruct H as [Hl Hp]. split; [exact Hl |]. apply Nat.eqb_neq. destruct (Nat.eqb y x) eqn:E; [| reflexivity]. simpl in Hp. discriminate Hp. Qed. Lemma filter_neq_in : forall y x l, In y l -> y <> x -> In y (filter (fun z => negb (Nat.eqb z x)) l). Proof. intros y x l Hl Hne. apply filter_In. split; [exact Hl |]. apply Nat.eqb_neq in Hne. rewrite Hne. reflexivity. Qed. Lemma nplug_fv_mono : forall C t s, incl (nfv t) (nfv s) -> incl (nfv (nplug C t)) (nfv (nplug C s)). Proof. induction C; intros t s Hincl; unfold incl in *; simpl in *. - apply Hincl. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. apply (IHC t s Hincl). exact Hy. + apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. exact Hy. + apply in_app_iff. right. apply (IHC t s Hincl). exact Hy. - intros y Hy. apply in_filter_neq in Hy as [Hy Hne]. apply filter_neq_in. + apply (IHC t s Hincl). exact Hy. + exact Hne. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. apply in_filter_neq in Hy as [Hy Hne]. apply filter_neq_in. * apply (IHC t s Hincl). exact Hy. * exact Hne. + apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. exact Hy. + apply in_app_iff. right. apply (IHC t s Hincl). exact Hy. Qed. Lemma nplug_fv_upper : forall C t s, incl (nfv (nplug C t)) (nfv (nplug C s) ++ nfv t). Proof. induction C; intros t s; unfold incl in *; simpl in *. - intros y Hy. apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply (IHC t s) in Hy. apply in_app_iff in Hy as [Hy|Hy]. * apply in_app_iff. left. apply in_app_iff. left. exact Hy. * apply in_app_iff. right. exact Hy. + apply in_app_iff. left. apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. apply in_app_iff. left. exact Hy. + apply (IHC t s) in Hy. apply in_app_iff in Hy as [Hy|Hy]. * apply in_app_iff. left. apply in_app_iff. right. exact Hy. * apply in_app_iff. right. exact Hy. - intros y Hy. apply in_filter_neq in Hy as [Hy Hne]. apply (IHC t s) in Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. apply filter_neq_in; [exact Hy | exact Hne]. + apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_filter_neq in Hy as [Hy Hne]. apply (IHC t s) in Hy. apply in_app_iff in Hy as [Hy|Hy]. * apply in_app_iff. left. apply in_app_iff. left. apply filter_neq_in; [exact Hy | exact Hne]. * apply in_app_iff. right. exact Hy. + apply in_app_iff. left. apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_app_iff. left. apply in_app_iff. left. exact Hy. + apply (IHC t s) in Hy. apply in_app_iff in Hy as [Hy|Hy]. * apply in_app_iff. left. apply in_app_iff. right. exact Hy. * apply in_app_iff. right. exact Hy. Qed. Inductive nred_core : ntrm -> ntrm -> Prop := | ncore_B : forall t x u, nred_core (NApp (NLam x t) u) (NESub t x u) | ncore_Gc : forall t x u, ~ In x (nfv t) -> nred_core (NESub t x u) t | ncore_R : forall C x u phi, In x phi -> (forall y, In y (nfv u) -> In y phi) -> cavoid C phi = true -> nred_core (NESub (nplug C (NVar x)) x u) (NESub (nplug C u) x u) | ncore_ctx : forall C t t', nred_core t t' -> nred_core (nplug C t) (nplug C t'). Lemma nred_core_fv : forall t t', nred_core t t' -> incl (nfv t') (nfv t). Proof. intros t t' H. induction H; simpl; unfold incl in *. - intros y Hy. exact Hy. - intros y Hy. apply in_app_iff. left. apply filter_neq_in; [exact Hy | intro E; apply H; subst; exact Hy]. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_filter_neq in Hy as [Hy Hne]. apply (nplug_fv_upper C u (NVar x)) in Hy. apply in_app_iff in Hy as [Hy|Hy]. * apply in_app_iff. left. apply filter_neq_in; [exact Hy | exact Hne]. * apply in_app_iff. right. exact Hy. + apply in_app_iff. right. exact Hy. - apply nplug_fv_mono. exact IHnred_core. Qed. Print Assumptions nplug_fv_mono. Print Assumptions nplug_fv_upper. Print Assumptions nred_core_fv. Lemma nplug_esub_fv : forall C X d x u y, y <> x -> In y (nfv (nplug C (NESub (NMVar X d) x u))) -> In y (nfv (nplug C (NMVar X d))) \/ In y (nfv u). Proof. induction C; intros X d x u y Hne Hy; simpl in *. - apply in_app_iff in Hy as [Hy|Hy]. + left. apply in_filter_neq in Hy as [Hy _]. simpl. exact Hy. + right. exact Hy. - apply in_app_iff in Hy as [Hy|Hy]. + apply (IHC X d x u y Hne) in Hy. destruct Hy as [Hy|Hy]. * left. apply in_app_iff. left. exact Hy. * right. exact Hy. + left. apply in_app_iff. right. exact Hy. - apply in_app_iff in Hy as [Hy|Hy]. + left. apply in_app_iff. left. exact Hy. + apply (IHC X d x u y Hne) in Hy. destruct Hy as [Hy|Hy]. * left. apply in_app_iff. right. exact Hy. * right. exact Hy. - apply in_filter_neq in Hy as [Hy Hz]. apply (IHC X d x u y Hne) in Hy. destruct Hy as [Hy|Hy]. + left. apply filter_neq_in; [exact Hy | exact Hz]. + right. exact Hy. - apply in_app_iff in Hy as [Hy|Hy]. + apply in_filter_neq in Hy as [Hy Hz]. apply (IHC X d x u y Hne) in Hy. destruct Hy as [Hy|Hy]. * left. apply in_app_iff. left. apply filter_neq_in; [exact Hy | exact Hz]. * right. exact Hy. + left. apply in_app_iff. right. exact Hy. - apply in_app_iff in Hy as [Hy|Hy]. + left. apply in_app_iff. left. exact Hy. + apply (IHC X d x u y Hne) in Hy. destruct Hy as [Hy|Hy]. * left. apply in_app_iff. right. exact Hy. * right. exact Hy. Qed. Lemma nred_fv : forall t t', nred t t' -> incl (nfv t') (nfv t). Proof. intros t t' H. induction H; simpl; unfold incl in *. - intros y Hy. exact Hy. - intros y Hy. apply in_app_iff. left. apply filter_neq_in; [exact Hy | intro E; apply H; subst; exact Hy]. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_filter_neq in Hy as [Hy Hne]. apply (nplug_esub_fv C X d x u y Hne) in Hy. destruct Hy as [Hy|Hy]. * apply in_app_iff. left. apply filter_neq_in; [exact Hy | exact Hne]. * apply in_app_iff. right. exact Hy. + apply in_app_iff. right. exact Hy. - intros y Hy. apply in_app_iff in Hy as [Hy|Hy]. + apply in_filter_neq in Hy as [Hy Hne]. apply (nplug_fv_upper C u (NVar x)) in Hy. apply in_app_iff in Hy as [Hy|Hy]. * apply in_app_iff. left. apply filter_neq_in; [exact Hy | exact Hne]. * apply in_app_iff. right. exact Hy. + apply in_app_iff. right. exact Hy. - apply nplug_fv_mono. exact IHnred. Qed. Print Assumptions nplug_esub_fv. Print Assumptions nred_fv. Lemma in_filter_neq_iff : forall z a l, In z (filter (fun w => negb (Nat.eqb w a)) l) <-> In z l /\ z <> a. Proof. intros z a l. split. - intro H. apply filter_In in H. destruct H as [Hl Hp]. split; [exact Hl |]. apply Nat.eqb_neq. destruct (Nat.eqb z a) eqn:E; [| reflexivity]. simpl in Hp. discriminate Hp. - intros [Hl Hne]. apply filter_In. split; [exact Hl |]. apply Nat.eqb_neq in Hne. rewrite Hne. reflexivity. Qed. Lemma Es_fv_both : forall t u, Es t u -> incl (nfv t) (nfv u) /\ incl (nfv u) (nfv t). Proof. apply Es_ind. - intros t0. split; unfold incl; auto. - intros t0 u0 H1 IH1. split. + apply (proj2 IH1). + apply (proj1 IH1). - intros t0 u0 v0 H1 H2 IH1 IH2. split. + intros z Hz. apply (proj1 IH2). apply (proj1 H2). exact Hz. + intros z Hz. apply (proj2 H2). apply (proj2 IH2). exact Hz. - intros t0 x0 u0 y0 v0 Hyx Hyu Hxv. split; unfold incl; intros z Hz; simpl in *; apply in_app_iff in Hz as [Hz|Hz]. + apply in_filter_neq_iff in Hz as [Hz Hy]. apply in_app_iff in Hz as [Hz|Hz]. * apply in_filter_neq_iff in Hz as [Hz Hx]. apply in_app_iff. left. apply in_filter_neq_iff. split; [| exact Hx]. apply in_app_iff. left. apply in_filter_neq_iff. split; [exact Hz | exact Hy]. * apply in_app_iff. right. exact Hz. + apply in_app_iff. left. apply in_filter_neq_iff. split; [| ]. * apply in_app_iff. right. exact Hz. * intro E. apply Hxv. subst z. exact Hz. + apply in_filter_neq_iff in Hz as [Hz Hx]. apply in_app_iff in Hz as [Hz|Hz]. * apply in_filter_neq_iff in Hz as [Hz Hy]. apply in_app_iff. left. apply in_filter_neq_iff. split; [| exact Hy]. apply in_app_iff. left. apply in_filter_neq_iff. split; [exact Hz | exact Hx]. * apply in_app_iff. right. exact Hz. + apply in_app_iff. left. apply in_filter_neq_iff. split; [| ]. * apply in_app_iff. right. exact Hz. * intro E. apply Hyu. subst z. exact Hz. - intros C0 t0 t0' H1 IH1. split; apply nplug_fv_mono. + apply (proj1 IH1). + apply (proj2 IH1). Qed. Lemma Es_fv : forall t u, Es t u -> forall z, In z (nfv t) <-> In z (nfv u). Proof. intros t u H z. destruct (Es_fv_both t u H) as [Htu Hut]. split. - apply Htu. - apply Hut. Qed. Print Assumptions in_filter_neq_iff. Print Assumptions Es_fv.