Require Import Tactics Encodings DecidableRecognisable.
Implicit Type p : term -> Prop.
Implicit Types s t u : term.

# Reduction lemma and Rice’s theorem

## Closedness is decidable

Definition Leb := Eval cbn in
rho (.\ "leb", "m", "n"; "m" !T (.\ "m'"; "n" !F (.\ "n'"; "leb" "m'" "n'"))).

Hint Unfold Leb: cbv.

Lemma Leb_correct m n : Leb (enc m) (enc n) benc (leb m n).
Proof.
destruct m.
- solveeq.
- revert m; induction n; intros m.
+ solveeq.
+ destruct m. solveeq. specialize (IHn m). solveeq.
Qed.

Hint Rewrite Leb_correct : Lcorrect.

Definition Lt : term := .\ "m", "n"; !Leb (!Succ "m") "n".

Lemma Lt_correct n k : Lt (enc n) (enc k) benc (Nat.ltb n k).
Proof.
unfold Nat.ltb. rewrite <- Leb_correct.
transitivity (Leb (Succ (enc n)) (enc k)). solveeq.
now rewrite Succ_correct.
Qed.

Definition Bound := Eval cbn in
rho (.\ "d", "k", "t";
"t" (.\ "n"; !Lt "n" "k")
(.\ "s", "t"; ("d" "k" "s") ("d" "k" "t") !F)
(.\ "s"; "d" (!Succ "k") "s")).

Lemma Bound_correct k s : Bound (enc k) (tenc s) benc (bound k s).
Proof.
revert k; induction s; intros k.
- transitivity (Lt (enc n) (enc k)). solveeq. rewrite Lt_correct. unfold bound.
destruct (Nat.ltb_spec0 n k); decide (n < k); try now omega. reflexivity. reflexivity.
- transitivity ((Bound (enc k) (tenc s1)) (Bound (enc k) (tenc s2)) F). solveeq.
rewrite IHs1, IHs2. cbn.
destruct (bound _ s1), (bound _ s2); solveeq.
- transitivity (Bound (Succ (enc k)) (tenc s)). solveeq. now rewrite Succ_correct, IHs.
Qed.

Definition Closed := Bound (enc 0).

Lemma decidable_closed : decidable closed.
Proof.
exists (lambda (Closed 0)). split; value.
intros s.
assert ((lambda (Closed 0)) (tenc s) benc (bound 0 s)).
transitivity (Bound (enc 0) (tenc s)). solveeq. now rewrite Bound_correct.
rewrite H.

destruct (bound 0 s) eqn:E.
- firstorder econstructor.
- right. split. intros C. congruence. econstructor.
Qed.

Definition Lambda := lambda (0 (lambda F) (lambda (lambda F)) (lambda T)).

Hint Unfold Lambda : cbv.

Lemma Lambda_correct s : Lambda (tenc s) T /\ lam s \/
Lambda (tenc s) F /\ ~ lam s.
Proof.
destruct s.
+ right. split. solveeq. intros [x H]; inv H.
+ right. split. solveeq. intros [x H]; inv H.
+ left. split. solveeq. value.
Qed.

Lemma decidable_lam : decidable lam.
Proof.
exists Lambda. split; value. intros s.
assert (H := Lambda_correct s). firstorder.
Qed.

Lemma decidable_proc : decidable proc.
Proof.
eapply decidable_intersection.
- eapply decidable_closed.
- eapply decidable_lam.
Qed.

## Reduction lemma

Notation "s '≈' t" := (forall u v, t (tenc u) v <-> s (tenc u) v) (at level 50).

Lemma equiv_semantic s t : s t -> s t.
Proof.
intros H ? ?; now rewrite H.
Qed.

Definition closed_under_proc R p := forall s t , proc s -> proc t -> p s -> R s t -> p t.
Definition semantic p := closed_under_proc (fun s t => s t) p.

Lemma unrecognisable_russell : ~ recognisable (fun s => closed s /\ ~ eva (s (tenc s))).
Proof.
intros [u [[cls_u lam_u] H]]. specialize (H u). tauto.
Qed.

Lemma Reduction p f v :
proc v ->
(forall s, closed s -> p (f s) <-> ~ eva (s (tenc s))) ->
(forall s, v (tenc s) tenc (f s)) ->
~ recognisable p.
Proof.
intros proc_v spec_f spec_v (u & proc_u & Hu).
assert (recognisable closed) as (C & proc_C & HC). {
eapply dec_recognisable. eapply decidable_closed. }
pose (w := lambda (F (C 0) (u (v 0)))).
eapply unrecognisable_russell. exists w; split; value. intros s.

assert (w (tenc s) F (C (tenc s)) (u (tenc (f s)))). {
transitivity (F (C (tenc s)) (u (v (tenc s)))). solveeq. now rewrite spec_v. }
intuition; [ | rewrite H, F_eva, <- HC, <- Hu, spec_f in H0; tauto..].
rewrite H, F_eva, <- HC, <- Hu, spec_f; eauto.
Qed.

## Rice's lemma and Rice's theorem

Lemma D_pi u : pi D u <-> False.
Proof.
unfold pi. firstorder using eva_D.
Qed.

Lemma Rice p N :
semantic p ->
proc N -> ~ p N ->
p D ->
~ recognisable p.
Proof with eauto; try now intuition.
intros p_sem proc_N pN pD [u [[cls_u lam_u] Hu]].
pose (f := fun s => lambda (F (s (tenc s)) N 0)).
pose (v := lambda (Lam (App (App (App (tenc F) (App 0 (Q 0))) (tenc N)) (tenc 0)))).

eapply Reduction with (p := p) (f := f) (v := v).
- value.
- intros. assert (Hf : forall t, f s (tenc t) F (s (tenc s)) N (tenc t)) by (intros; solvered).
intuition.
+ eapply p_sem in H0; value. eapply pN, H0. intros t t'. rewrite Hf.
destruct H1 as (s' & [] % evaluates_equiv). rewrite H1, F_correct; value. tauto.
+ eapply p_sem with (s := D); value. eauto. intros t t'. rewrite Hf.
intuition.
* destruct H0. eapply F_eva with (t := N). eapply app_eva with (t := tenc t). firstorder.
* exfalso. eapply D_pi. exists t'. eassumption.
- intros. transitivity (Lam ((App ((App ((App (tenc F)) ((App (tenc s)) (Q (tenc s))))) (tenc N))) (tenc 0))). solveeq.
now rewrite Q_correct, !App_correct, Lam_correct.
- exists u. firstorder.
Qed.

Lemma Rice_pi p :
closed_under_proc (fun s t => (forall u, pi s u <-> pi t u)) p ->
(exists u, proc u /\ ~ p u) ->
p (lambda Omega) -> ~ recognisable p.
Proof with eauto; try now intuition.
intros. destruct H0 as [u [H0 H0']]. eapply Rice.
- intros. hnf. intuition. eapply H. exact H2. eauto. eauto. split; intros (? & ?); exists x; firstorder.
- eauto.
- eauto.
- firstorder.
Qed.

Lemma rec_total : ~ recognisable (fun s => ~forall t, pi s t).
Proof.
eapply Rice_pi.
- hnf; intuition. eapply H1. intros. rewrite H2. eauto.
- exists (lambda I). repeat split; value. intros H. eapply H. intros t. exists I. solveeq.
- intros A. eapply (D_pi I); eauto.
Qed.

Lemma rec_total_cls : ~ recognisable (fun s => closed s /\ ~forall t, pi s t).
Proof.
eapply Rice_pi.
- hnf; intuition. eapply H4. intros. rewrite H2. eauto.
- exists (lambda I). repeat split; value. intros H. eapply H. intros t. exists I. solveeq.
- split; value. intros A. eapply (D_pi I); eauto.
Qed.

Lemma rec_total_proc : ~ recognisable (fun s => proc s /\ ~forall t, pi s t).
Proof.
eapply Rice_pi.
- hnf; intuition. eapply H4. intros. rewrite H2. eauto.
- exists (lambda I). repeat split; value. intros H. eapply H. intros t. exists I. solveeq.
- split; value. intros A. eapply (D_pi I); eauto.
Qed.

Theorem Rice_Theorem p :
closed_under_proc (fun s t => s t) p ->
(exists u, proc u /\ ~ p u) -> (exists u, proc u /\ p u) ->
~ decidable p.
Proof.
intros. intros A. assert (B : decidable p) by eassumption. destruct A as [u [proc_u Hu]].
destruct H0 as (? & ? & ?), H1 as (? & ? & ?).
destruct (Hu D).
- eapply Rice. exact H. exact H0. tauto. firstorder. eapply dec_recognisable. exists u; tauto.
- eapply Rice with (p := complement p).
+ unfold complement. hnf. intuition. eapply H8. eapply H; eauto. intuition; now eapply H9.
+ exact H1.
+ firstorder.
+ firstorder.
+ now eapply dec_recognisable, decidable_complement.
Qed.

Lemma dec_total : ~ decidable (fun s => proc s /\ forall t, pi s t).
Proof.
eapply Rice_Theorem.
- hnf; intuition. destruct (H4 t0). firstorder.
- exists D. repeat split; value. intros A. eapply (D_pi I); eauto. firstorder.
- exists (lambda I). repeat split; value. intros H. exists I. solveeq.
Qed.