Require Undecidability.L.L.
From Undecidability.LambdaCalculus Require Import Krivine Lambda Util.Krivine_facts.
Require Import Undecidability.LambdaCalculus.Util.term_facts.
Require Import Undecidability.Shared.deterministic_simulation.
Require Import Relations List.
Import L (term, var, app, lam).
Import ListNotations TermNotations.
Require Import ssreflect.
Set Default Goal Selector "!".
Lemma t_step' {X : Type} (R : X -> X -> Prop) x y z :
R x y -> clos_refl_trans _ R y z -> clos_trans _ R x z.
Proof.
move=> H /clos_rt_rt1n_iff H'.
elim: H' x H; by eauto using clos_trans.
Qed.
Lemma rt_step' {X : Type} (R : X -> X -> Prop) x y z :
R x y -> clos_refl_trans _ R y z -> clos_refl_trans _ R x z.
Proof. by eauto using clos_refl_trans. Qed.
Inductive step' : term -> term -> Prop :=
| step'Lam s t : normal_form s -> normal_form t -> step' (app (lam s) t) (subst (scons t (fun x => var x)) s)
| step'App s s' t : normal_form t -> step' s s' -> step' (app s t) (app s' t).
#[local] Notation steps' := (clos_trans _ step').
Lemma step'E M N : step' M N ->
match M with
| var _ => False
| app M1 M2 => normal_form M2 /\
match M1 with
| var _ => False
| app _ _ => exists M', step' M1 M'
| lam M3 => normal_form M3 /\ N = (subst (scons M2 var) M3)
end
| lam _ => False
end.
Proof.
case; [tauto|case].
- move=> > _ H. inversion H.
- move=> *. split; [|eexists]; eassumption.
- move=> > _ H. inversion H.
Qed.
Lemma step'_step_det M N : step' M N -> forall N', step M N' -> N = N'.
Proof.
elim.
- move=> {}M {}N HM HN N'.
move E: (app (lam M) N) => M' H. case: H E.
+ congruence.
+ move=> > /normal_form_not_step H [] ??. subst.
case: H. by constructor.
+ move=> > /normal_form_not_step H [] ??. by subst.
+ done.
- move=> M1 M2 {}N HN HM1M2 HM1 N'.
move E: (app M1 N) => M' H. case: H E.
+ move=> > [] ??. subst.
by move=> /step'E in HM1M2.
+ move=> > H [] ??. subst. congr app.
by apply: HM1.
+ move=> > /normal_form_not_step ? [] ??. by subst.
+ done.
Qed.
Lemma step'_step M N : step' M N -> step M N.
Proof.
elim=> *.
- by apply: stepSubst.
- by apply: stepAppL.
Qed.
Lemma step'_det M N N' : step' M N -> step' M N' -> N = N'.
Proof.
move=> /step'_step_det H /step'_step. by apply: H.
Qed.
#[local] Notation I := (lam (var 0)).
#[local] Notation call Ns := (lam (many_app (var 0) (Ns ++ [var 0]))).
Fixpoint enc_nat (n : nat) : term :=
match n with
| 0 => lam (lam (call [var 2]))
| S n => lam (lam (call [var 1; enc_nat n]))
end.
Fixpoint enc_term (M : term) :=
match M with
| var x => lam (lam (lam (call [var 3; enc_nat x])))
| app M N => lam (lam (lam (call [var 2; enc_term M; enc_term N])))
| lam M => lam (lam (lam (call [var 1; enc_term M])))
end.
Definition enc_list {X : Type} (f : X -> term) :=
fix rec (l : list X) :=
match l with
| nil => lam (lam (call [var 2]))
| cons x l => lam (lam (call [var 1; f x; rec l]))
end.
Fixpoint enc_eterm (P : eterm) :=
match P with
| closure Ps M => lam (call [var 1; enc_list enc_eterm Ps; enc_term M])
end.
Lemma normal_form_enc_nat n : normal_form (enc_nat n).
Proof. elim: n; by do ? constructor. Qed.
#[local] Hint Resolve normal_form_enc_nat : core.
Lemma normal_form_enc_term M : normal_form (enc_term M).
Proof. elim: M; by do ? constructor. Qed.
#[local] Hint Resolve normal_form_enc_term : core.
Lemma normal_form_enc_list {X: Type} (f : X -> term) l : (forall x, normal_form (f x)) -> normal_form (enc_list f l).
Proof. move=> Hf. elim: l; by do ? constructor. Qed.
Lemma normal_form_enc_eterm P : normal_form (enc_eterm P).
Proof.
elim /Krivine_facts.eterm_ind': P.
move=> ?? H /=. do ? constructor; [|done].
elim: H; by do ? constructor.
Qed.
#[local] Hint Resolve normal_form_enc_eterm : core.
Lemma normal_form_enc_eterms Ps : normal_form (enc_list enc_eterm Ps).
Proof. by apply: normal_form_enc_list. Qed.
#[local] Hint Resolve normal_form_enc_eterms : core.
Lemma ren_enc_nat xi n : ren xi (enc_nat n) = enc_nat n.
Proof. elim: n xi; cbn; congruence. Qed.
Lemma subst_enc_nat sigma n : subst sigma (enc_nat n) = enc_nat n.
Proof. elim: n sigma; cbn; congruence. Qed.
Lemma ren_enc_term xi M : ren xi (enc_term M) = enc_term M.
Proof. elim: M xi; intros; cbn; rewrite ?ren_enc_nat; congruence. Qed.
Lemma subst_enc_term sigma M : subst sigma (enc_term M) = enc_term M.
Proof. elim: M sigma; intros; cbn; rewrite ?subst_enc_nat; congruence. Qed.
Lemma ren_enc_list {X: Type} (f : X -> term) xi l : (Forall (fun x => forall xi, ren xi (f x) = f x) l) ->
ren xi (enc_list f l) = enc_list f l.
Proof. move=> H. elim: H xi; cbn; congruence. Qed.
Lemma subst_enc_list {X: Type} (f : X -> term) sigma l : (Forall (fun x => forall sigma, subst sigma (f x) = f x) l) ->
subst sigma (enc_list f l) = enc_list f l.
Proof. move=> H. elim: H sigma; cbn; congruence. Qed.
Lemma ren_enc_eterm xi P : ren xi (enc_eterm P) = enc_eterm P.
Proof.
elim /Krivine_facts.eterm_ind': P xi.
move=> Ps t IH xi /=.
do ? congr lam. do ? congr app.
- by apply: ren_enc_list.
- by apply: ren_enc_term.
Qed.
Lemma subst_enc_eterm sigma P : subst sigma (enc_eterm P) = enc_eterm P.
Proof.
elim /Krivine_facts.eterm_ind': P sigma.
move=> Ps t IH xi /=.
do ? congr lam. do ? congr app.
- by apply: subst_enc_list.
- by apply: subst_enc_term.
Qed.
Lemma ren_enc_eterms xi l : ren xi (enc_list enc_eterm l) = enc_list enc_eterm l.
Proof. apply: ren_enc_list. apply /Forall_forall=> *. by apply: ren_enc_eterm. Qed.
Lemma subst_enc_eterms sigma l : subst sigma (enc_list enc_eterm l) = enc_list enc_eterm l.
Proof. apply: subst_enc_list. apply /Forall_forall=> *. by apply: subst_enc_eterm. Qed.
Definition subst_enc := (
subst_enc_eterms, subst_enc_eterm, subst_enc_term, subst_enc_nat,
ren_enc_eterms, ren_enc_eterm, ren_enc_term, ren_enc_nat).
Definition enc_halt_cbn_var0 :=
lam (lam (lam (
call [var 2;
I;
lam (lam (call [var 2; lam (lam (call [var 7; var 9; var 2; var 1; var 7]))]))
]))).
Definition enc_halt_cbn_varS :=
lam (lam (lam (lam (
call [var 3;
I;
lam (lam (call [var 4; var 7; var 1; lam (lam (lam (call [var 3; var 9]))); var 4]))
])))).
Definition enc_halt_cbn_app :=
lam (lam (lam (lam (lam (
call [var 1; lam (lam (call [var 1; lam (call [var 1; var 9; var 7]); var 8])); var 4; var 3; var 1]
))))).
Definition enc_halt_cbn_lam :=
lam (lam (lam (lam (
call [var 4;
I;
lam (lam (call [var 4; var 1; lam (lam (call [var 1; var 5; var 9])); var 5; var 4]))
])))).
Lemma enc_halt_cbn_var0_spec ts ctx t ctx' rec :
normal_form rec ->
(forall xi, ren xi rec = rec) ->
(forall sigma, subst sigma rec = rec) ->
clos_refl_trans _ step'
(many_app enc_halt_cbn_var0 [enc_list enc_eterm ts; enc_list enc_eterm ((closure ctx t)::ctx'); rec; I])
(many_app rec [enc_list enc_eterm ts; enc_list enc_eterm ctx; enc_term t; rec; I]).
Proof.
move=> H1r H2r H3r.
do ? (apply: rt_step'; [by do ? constructor|]; rewrite /= ?subst_enc ?H2r ?H3r).
by apply: rt_refl.
Qed.
Lemma enc_halt_cbn_varS_spec ts P ctx x rec :
normal_form rec ->
(forall xi, ren xi rec = rec) ->
(forall sigma, subst sigma rec = rec) ->
clos_refl_trans _ step'
(many_app enc_halt_cbn_varS [enc_list enc_eterm ts; enc_list enc_eterm (P::ctx); enc_nat x; rec; I])
(many_app rec [enc_list enc_eterm ts; enc_list enc_eterm ctx; enc_term (var x); rec; I]).
Proof.
move=> H1r H2r H3r.
do ? (apply: rt_step'; [by do ? constructor|]; rewrite /= ?subst_enc ?H2r ?H3r).
by apply: rt_refl.
Qed.
Lemma enc_halt_cbn_app_spec ts ctx s t rec :
normal_form rec ->
(forall xi, ren xi rec = rec) ->
(forall sigma, subst sigma rec = rec) ->
clos_refl_trans _ step'
(many_app enc_halt_cbn_app [enc_list enc_eterm ts; enc_list enc_eterm ctx; enc_term s; enc_term t; rec; I])
(many_app rec [enc_list enc_eterm ((closure ctx t)::ts); enc_list enc_eterm ctx; enc_term s; rec; I]).
Proof.
move=> H1r H2r H3r.
do ? (apply: rt_step'; [by do ? constructor|]; rewrite /= ?subst_enc ?H2r ?H3r).
by apply: rt_refl.
Qed.
Lemma enc_halt_cbn_lam_spec ts ctx s t rec :
normal_form rec ->
(forall xi, ren xi rec = rec) ->
(forall sigma, subst sigma rec = rec) ->
clos_refl_trans _ step'
(many_app enc_halt_cbn_lam [enc_list enc_eterm (t::ts); enc_list enc_eterm ctx; enc_term s; rec; I])
(many_app rec [enc_list enc_eterm ts; enc_list enc_eterm (t::ctx); enc_term s; rec; I]).
Proof.
move=> H1r H2r H3r.
do ? (apply: rt_step'; [by do ? constructor|]; rewrite /= ?subst_enc ?H2r ?H3r).
by apply: rt_refl.
Qed.
Lemma enc_halt_cbn_lam_spec' ctx s rec :
normal_form rec ->
(forall xi, ren xi rec = rec) ->
(forall sigma, subst sigma rec = rec) ->
clos_refl_trans _ step'
(many_app enc_halt_cbn_lam [enc_list enc_eterm nil; enc_list enc_eterm ctx; enc_term s; rec; I])
I.
Proof.
move=> H1r H2r H3r.
do ? (apply: rt_step'; [by do ? constructor|]; rewrite /= ?subst_enc ?H2r ?H3r).
by apply: rt_refl.
Qed.
Definition enc_halt_cbn : term :=
lam (lam (lam (lam (
call [var 2 ;
lam (call [var 1;
call [enc_halt_cbn_var0; var 7 ; var 6 ; var 4 ];
lam (call [enc_halt_cbn_varS; var 8 ; var 7 ; var 1 ; var 5 ])
]);
lam (lam (call [enc_halt_cbn_app; var 7 ; var 6 ; var 2 ; var 1 ; var 4 ]));
lam (call [enc_halt_cbn_lam; var 6 ; var 5 ; var 1 ; var 3 ])
])))).
Lemma normal_form_enc_halt_cbn_var0 : normal_form enc_halt_cbn_var0.
Proof. by do ? constructor. Qed.
Lemma normal_form_enc_halt_cbn_varS : normal_form enc_halt_cbn_varS.
Proof. by do ? constructor. Qed.
Lemma normal_form_enc_halt_cbn_app : normal_form enc_halt_cbn_app.
Proof. by do ? constructor. Qed.
Lemma normal_form_enc_halt_cbn_lam : normal_form enc_halt_cbn_lam.
Proof. by do ? constructor. Qed.
Lemma ren_enc_halt_cbn xi : ren xi enc_halt_cbn = enc_halt_cbn.
Proof. done. Qed.
Lemma subst_enc_halt_cbn sigma : subst sigma enc_halt_cbn = enc_halt_cbn.
Proof. done. Qed.
Lemma subst_enc_halt_cbn_var0 sigma : subst sigma enc_halt_cbn_var0 = enc_halt_cbn_var0.
Proof. done. Qed.
Lemma subst_enc_halt_cbn_varS sigma : subst sigma enc_halt_cbn_varS = enc_halt_cbn_varS.
Proof. done. Qed.
Lemma subst_enc_halt_cbn_app sigma : subst sigma enc_halt_cbn_app = enc_halt_cbn_app.
Proof. done. Qed.
Lemma subst_enc_enc_halt_cbn_lam sigma : subst sigma enc_halt_cbn_lam = enc_halt_cbn_lam.
Proof. done. Qed.
Definition simpl_term := (
subst_enc,
subst_enc_halt_cbn_var0, subst_enc_halt_cbn_varS, subst_enc_halt_cbn_app, subst_enc_enc_halt_cbn_lam).
#[local] Hint Resolve
normal_form_enc_halt_cbn_var0
normal_form_enc_halt_cbn_varS
normal_form_enc_halt_cbn_app
normal_form_enc_halt_cbn_lam
: core.
Opaque enc_halt_cbn_var0 enc_halt_cbn_varS enc_halt_cbn_app enc_halt_cbn_lam.
Opaque enc_eterm enc_list.
#[local] Notation enc_state ts ctx t :=
(many_app enc_halt_cbn [enc_list enc_eterm ts; enc_list enc_eterm ctx; enc_term t; enc_halt_cbn; I]).
Inductive sync : (list eterm * list eterm * term) -> term -> Prop :=
sync_intro ts ctx t : sync (ts, ctx, t) (enc_state ts ctx t).
Lemma syncE X X' : sync X X' ->
match X with
| (ts, ctx, t) => X' = many_app enc_halt_cbn [enc_list enc_eterm ts; enc_list enc_eterm ctx; enc_term t; enc_halt_cbn; I]
end.
Proof. by case. Qed.
Lemma Krivine_step_dec X : (exists Y, Krivine_step X Y) \/ (stuck Krivine_step X).
Proof.
move: X => [[ts ctx] t].
move: t => [[|?]|??|?].
- move: ctx => [|[??]?].
+ right. move=> ? H. by inversion H.
+ left. eexists. by constructor.
- move: ctx=> [|??].
+ right. move=> ? H. by inversion H.
+ left. eexists. by constructor.
- left. eexists. by constructor.
- move: ts => [|??].
+ right. move=> ? H. by inversion H.
+ left. eexists. by constructor.
Qed.
Lemma Krivine_step_steps' X Y X' :
Krivine_step X Y ->
sync X X' ->
exists Y', steps' X' Y' /\ sync Y Y'.
Proof.
have := subst_enc_halt_cbn.
have := ren_enc_halt_cbn.
move E: enc_halt_cbn => rec.
have H'rec : normal_form rec by (rewrite -E; do ? constructor).
move=> H1rec H2rec.
case=> > /syncE ->; eexists; (split; [|by apply: sync_intro]); rewrite !E.
all: rewrite -[l in steps' (many_app l _) _]E /enc_halt_cbn.
- do ? ((apply: rt_step' || apply: t_step'); [by do ? constructor|]; rewrite /= ?simpl_term ?H1rec ?H2rec).
by apply: enc_halt_cbn_var0_spec.
- do ? ((apply: rt_step' || apply: t_step'); [by do ? constructor|]; rewrite /= ?simpl_term ?H1rec ?H2rec).
by apply: enc_halt_cbn_varS_spec.
- do ? ((apply: rt_step' || apply: t_step'); [by do ? constructor|]; rewrite /= ?simpl_term ?H1rec ?H2rec).
by apply: enc_halt_cbn_app_spec.
- do ? ((apply: rt_step' || apply: t_step'); [by do ? constructor|]; rewrite /= ?simpl_term ?H1rec ?H2rec).
by apply: enc_halt_cbn_lam_spec.
Qed.
Lemma subst_enc_state ts ctx t sigma : subst sigma (enc_state ts ctx t) = enc_state ts ctx t.
Proof. by rewrite /= ?simpl_term. Qed.
Lemma halt_cbn_rt_step' ts ctx t :
halt_cbn ts ctx t -> clos_refl_trans _ step' (enc_state ts ctx t) I.
Proof.
move=> /halt_cbn_Krivine_step.
move=> [ctx'] [t'] /(clos_refl_trans_transport Krivine_step_steps' (sync_intro _ _ _)) [?] [/syncE] -> ?.
apply: rt_trans; [eassumption|].
have := subst_enc_halt_cbn.
have := ren_enc_halt_cbn.
move E: enc_halt_cbn => rec.
have H'rec : normal_form rec by (rewrite -E; do ? constructor).
move=> H1rec H2rec.
rewrite -[l in many_app l _]E /enc_halt_cbn.
do ? (apply: rt_step'; [by do ? constructor|]; rewrite /= ?simpl_term ?H1rec ?H2rec).
by apply: enc_halt_cbn_lam_spec'.
Qed.
Lemma step'_step_SN t : clos_refl_trans _ step' t I -> Acc (fun x y => step y x) t.
Proof.
move E: (I) => t' /clos_rt_rt1n_iff H. elim: H E.
- move=> ? <-. constructor. move=> ?.
move E: (I) => ? H. exfalso. case: H E=> //.
by move=> > [].
- move=> > /step'_step_det H _ IH ?. subst. constructor.
move=> ? /H <-. by apply: IH.
Qed.
Lemma step'_dec s : (exists t, step' s t) \/ not (exists t, step' s t).
Proof.
elim: s.
- move=> ?. right. by move=> [?] /step'E.
- move=> [?|s1 s2|{}s] IHs {}t _.
+ right. by move=> [?] /step'E [].
+ have [?|?] := normal_form_dec t; first last.
{ right. move=> [?] /step'E. tauto. }
move: IHs => [[?] IHs|IHs].
* left. eexists. constructor; eassumption.
* right. by move=> [?] /step'E [?] /IHs.
+ have [?|?] := normal_form_dec t; first last.
{ right. move=> [?] /step'E. tauto. }
have [?|?] := normal_form_dec s; first last.
{ right. move=> [?] /step'E. tauto. }
left. eexists. by constructor.
- move=> ??. right. by move=> [?] /step'E.
Qed.
Lemma SN_terminates_step' t : Acc (fun x y => step y x) t -> terminates step' t.
Proof.
elim=> {}t _ IH. case: (step'_dec t).
- move=> [t'] /[dup] H /step'_step /IH [?] [??].
eexists. split; [|eassumption].
apply: rt_trans; [apply: rt_step|]; eassumption.
- move=> H. exists t. split; [apply: rt_refl|].
move=> ??. apply: H. eexists. eassumption.
Qed.
Require Import Undecidability.Synthetic.Definitions.
Theorem reduction : KrivineMclosed_HALT ⪯ SNclosed.
Proof.
exists (fun '(exist _ t _) => exist _ _ (subst_enc_state nil nil t)).
move=> [t Ht] /=. split.
- move=> ?. apply: step'_step_SN. by apply: halt_cbn_rt_step'.
- move=> /SN_terminates_step'.
move=> /(terminates_reflection step'_det Krivine_step_steps' Krivine_step_dec (sync_intro _ _ _)).
move=> [[[ts' ctx'] t']] [].
move=> /Krivine_step_halt_cbn'. apply; [by constructor|].
split; [|done].
apply /L_facts.closed_dcl. apply: term_facts.closed_I=> k.
by rewrite term_facts.L_subst_Lambda_subst; [|apply: Ht].
Qed.