Set Implicit Arguments.
Require Import RelationClasses Morphisms List Lia Init.Nat Setoid.
From Undecidability.HOU Require Import calculus.calculus second_order.diophantine_equations
systemunification nth_order_unification.
Import ListNotations.
Set Default Proof Using "Type".
Definition ag : Const :=
{|
const_type := option (option False);
ctype := fun o =>
match o with
| None => alpha → alpha → alpha
| Some None => alpha
| Some (Some f) => match f with end
end;
|}.
Notation g := (@const ag None).
Notation a := (@const ag (Some None)).
Lemma typing_a Gamma: Gamma ⊢(2) a : alpha.
Proof. econstructor; cbn; eauto. Qed.
Lemma typing_g Gamma: Gamma ⊢(2) g : alpha → alpha → alpha.
Proof. econstructor; cbn; eauto. Qed.
#[export] Hint Resolve typing_a typing_g : core.
Section Linearization.
Implicit Types (S: list (exp ag)).
Definition lin S t := AppL (map (app g) S) t.
Lemma lin_nil t: lin nil t = t.
Proof. reflexivity. Qed.
Lemma lin_cons s S t:
lin (s :: S) t = g s (lin S t).
Proof. reflexivity. Qed.
Lemma lin_app S1 S2 t:
lin (S1 ++ S2) t = lin S1 (lin S2 t).
Proof. unfold lin; simplify; now rewrite AppL_app. Qed.
Hint Rewrite lin_nil lin_cons lin_app : simplify.
Lemma lin_typing Gamma S t:
(Gamma ⊢₊(2) S : repeat alpha (length S)) ->
(Gamma ⊢(2) t : alpha) ->
Gamma ⊢(2) lin S t : alpha.
Proof.
intros ? ?. induction S as [|s S IH]; simplify; [eauto|]. inv H.
econstructor; cbn; eauto.
Qed.
Lemma lin_ren delta S t:
ren delta (lin S t) = lin (renL delta S) (ren delta t).
Proof. unfold lin; asimpl; now rewrite !map_map. Qed.
Lemma lin_subst sigma S t:
sigma • lin S t = lin (sigma •₊ S) (sigma • t).
Proof. unfold lin; asimpl; now rewrite !map_map. Qed.
Hint Rewrite lin_ren lin_subst : asimpl.
Lemma lin_injective S T s t:
length S = length T -> lin S s = lin T t -> S = T /\ s = t.
Proof.
induction S in T |-*; destruct T; try discriminate; simplify in *; eauto.
intros; edestruct IHS.
all: injection H as H; eauto.
all: injection H0; intuition; subst; intuition.
Qed.
Lemma largest_lin s:
exists S t, s = lin S t /\ forall s' t', t <> g s' t'.
Proof.
edestruct (AppL_largest s (P := fun (s: exp ag) => match s with app (const None) s => True | _ => False end))
as (S & t & H1 & H2 & H3).
intros [| | | [| [] | | ]]. 1 - 8: firstorder. subst.
enough (exists S', S = map (app g) S') as [S' ->].
exists S'. exists t. intuition. eapply H3; cbn; eauto; cbn; eauto.
clear H3. induction S. now (exists nil).
specialize (H1 a) as H2; mp H2; intuition; destruct a as [| | | [| [] | | ]]; intuition.
edestruct IHS as [S']; intros. eapply H1; intuition. subst. now (exists (a1 :: S')).
Qed.
Lemma lin_normal S t:
(forall s, s ∈ S -> normal s) -> normal t -> normal (lin S t).
Proof.
intros; induction S; cbn; [eauto|].
repeat apply normal_app_intro; eauto.
Qed.
End Linearization.
Global Hint Rewrite lin_ren lin_subst : asimpl.
Global Hint Rewrite lin_nil lin_cons lin_app : simplify.
Section Encoding.
Notation Succ := (g a).
Definition enc n s := lin (repeat a n) s.
Definition encodes s n := forall t delta, (ren delta s) t ≡ enc n t.
Arguments enc : simpl never.
Section enc_equations.
Lemma enc_zero t: enc 0 t = t.
Proof. reflexivity. Qed.
Hint Rewrite enc_zero : simplify.
Lemma enc_succ n t: enc (S n) t = Succ (enc n t).
Proof. reflexivity. Qed.
Hint Rewrite enc_succ : simplify.
Lemma enc_succ_out n t: enc n (Succ t) = Succ (enc n t).
Proof. induction n; simplify; congruence. Qed.
Hint Rewrite enc_succ_out : simplify.
Lemma enc_app n m t:
enc (n + m) t = enc n (enc m t).
Proof. induction n; cbn; simplify; congruence. Qed.
Hint Rewrite enc_app : simplify.
End enc_equations.
Hint Rewrite enc_app enc_succ_out enc_succ enc_zero : simplify.
Lemma enc_ren delta n s:
ren delta (enc n s) = enc n (ren delta s).
Proof.
unfold enc; asimpl; now rewrite repeated_map.
Qed.
Lemma enc_subst sigma n s:
sigma • enc n s = enc n (sigma • s).
Proof.
unfold enc; asimpl; now rewrite repeated_map.
Qed.
Hint Rewrite enc_ren enc_subst : asimpl.
Lemma enc_normal n s:
normal s -> normal (enc n s).
Proof.
intros; induction n; simplify.
- eauto.
- eapply normal_app_intro; [|eapply normal_app_intro|]; eauto.
Qed.
Hint Resolve enc_normal : core.
Lemma enc_injective n m s t:
isAtom s -> isAtom t -> enc n s ≡ enc m t -> n = m /\ s = t.
Proof.
induction n in m |-*; simplify in *; destruct m; simplify in *; intros.
- intuition. destruct s, t; cbn in *; intuition; try Discriminate; Injection H1; congruence.
- destruct s; cbn in *; intuition; Discriminate.
- destruct t; cbn in *; intuition; Discriminate.
- Injection H1. eapply IHn in H3; eauto.
intuition.
Qed.
Lemma enc_typing Gamma s n:
(Gamma ⊢(2) s : alpha) ->
Gamma ⊢(2) enc n s : alpha.
Proof.
intros; unfold enc.
eapply lin_typing; eauto.
eapply repeated_ordertyping; [|eauto].
intros ? <- % repeated_in.
econstructor; eauto.
Qed.
Global Instance enc_equiv: Proper (Logic.eq ++> equiv step ++> equiv step) enc.
Proof.
intros ?? -> ??; unfold enc, lin; now intros ->.
Qed.
Lemma dec_enc_eq :
forall s, { n | s = enc n a } + ({ n | s = enc n a } -> False).
Proof.
induction s as [| [[[]|]|] | | s1 IH1 s3 IH3].
all: try (right; intros [[|n] ]; cbn; discriminate).
- left. exists 0. reflexivity.
- destruct IH3 as [[n]|]; subst.
+ destruct s1 as [| | | s1 s2 ].
all: try (right; intros [[|n'] ]; cbn; discriminate).
destruct s1 as [| [[]|] | | ].
all: try (right; intros [[|n'] ]; cbn; discriminate).
destruct s2 as [| [[]|] | | ].
all: try (right; intros [[|n'] ]; cbn; discriminate).
left. exists (S n). reflexivity.
+ right. intros [n H].
destruct n; try discriminate; cbn in *; injection H.
intros; eapply f; subst; now (exists n).
Qed.
Lemma dec_enc:
forall s, normal s -> { n | s a ≡ enc n a } + ({ n | s a ≡ enc n a } -> False).
Proof.
intros s N. specialize (@red_fun_rho _ (@step ag) (@par ag) rho) as f.
do 4 mp f; try typeclasses eauto; eauto.
assert (s a ▷ rho (s a)).
- eapply id in f as g. destruct g as [H1 H2].
split; [eauto|]. destruct s; cbn.
+ eapply normal_app_intro; eauto.
+ eapply normal_app_intro; eauto.
+ eapply normal_subst.
1 - 2: intros []; cbn; eauto.
enough (rho s = s) as -> by eauto using normal_lam_elim.
eapply red_fun_fp; eauto using normal_lam_elim.
+ eapply head_atom in N as isA; [|eauto].
assert (rho s1 = s1) as -> by (eapply red_fun_fp; eauto using normal_app_l, normal_app_r).
assert (rho s2 = s2) as -> by (eapply red_fun_fp; eauto using normal_app_l, normal_app_r).
destruct s1; cbn in isA; intuition.
- destruct (dec_enc_eq (rho (s a))) as [[n H1]|H1].
+ left. exists n. rewrite H1 in H. eapply equiv_join. rewrite H. all: eauto.
+ right. intros [n H2]. eapply H1. exists n.
eapply equiv_unique_normal_forms; eauto. 2: eapply H. rewrite <-H2.
symmetry. eapply equiv_join. rewrite H. all: eauto.
Qed.
End Encoding.
#[export] Hint Resolve enc_normal : core.
Global Hint Rewrite enc_zero enc_succ enc_app enc_succ_out: simplify.
Global Hint Rewrite enc_ren enc_subst: asimpl.
Arguments enc : simpl never.
Notation Succ := (g a).
Lemma normal_forms_encodes s:
normal s -> lambda lambda (ren (add 2) s) (enc 1 (var 1)) ≡ lambda lambda Succ ((ren (add 2) s) (var 1)) ->
exists n, encodes s n.
Proof.
remember (add 2) as delta.
cbn; intros H EQ % equiv_lam_elim % equiv_lam_elim; destruct s; cbn in EQ.
- Injection EQ; Discriminate.
- Injection EQ; Discriminate.
- eapply equiv_reduce in EQ.
2, 3: dostep; asimpl; reflexivity.
eapply normal_lam_elim in H.
enough (exists n : nat, forall t delta, t .: delta >> var • s ≡ enc n t) as [n H'] by
(exists n; intros t delta'; asimpl; rewrite stepBeta; asimpl; eauto).
induction s as [[] | | |]; unfold funcomp in EQ; cbn in EQ.
+ now (exists 0).
+ Discriminate.
+ Discriminate.
+ Discriminate.
+ eapply head_atom in H as H'; cbn; intuition.
eapply equiv_app_elim in EQ as [EQ1 EQ2]; cbn; intuition.
2: eapply atom_head_lifting; eauto; intros []; cbn; intuition.
enough (s1 = g a).
* subst. cbn in EQ2.
eapply IHs2 in EQ2. 2: eauto using normal_app_r.
destruct EQ2. subst.
exists (S x). intros t delta; cbn; simplify; now rewrite H0.
* destruct s1 as [[] | | | t1 t2]; simplify in EQ1; cbn in *.
1 - 4: try Injection EQ1; Discriminate.
assert (isAtom (head (g a (var 1) .: delta >> var • t1)))
by (eapply atom_head_lifting; eauto; intros []; cbn; intuition).
Injection EQ1.
assert (isAtom (head t2)).
{ eapply head_atom. eauto using normal_app_r, normal_app_l.
intros ?; destruct t2; cbn in H2; intuition; Discriminate.
}
assert (isAtom (head (g a (var 1) .: delta >> var • t2)))
by (eapply atom_head_lifting; eauto; intros []; cbn; intuition).
destruct t1; cbn in *; try Discriminate.
destruct f; cbn in *; Discriminate.
destruct t2; cbn in *; try Discriminate.
destruct f; cbn in *; Discriminate.
Injection H1; subst.
Injection H2; subst.
reflexivity.
- eapply normal_ren with (delta := delta) in H.
eapply head_atom in H; eauto. cbn in EQ.
Injection EQ. Injection H0.
unshelve eapply ren_equiv_proper in H2;
[exact (pred >> pred)|exact (pred >> pred)|eauto..]; asimpl in H2.
unshelve eapply ren_equiv_proper in H3;
[exact (pred >> pred)|exact (pred >> pred)|eauto..]; asimpl in H3.
exists 1. intros t delta'; simplify. subst delta. asimpl in H3. asimpl in H2.
now rewrite H2, H3.
Qed.
Lemma encodes_characeristic s n:
encodes s n -> lambda lambda (ren (add 2) s) (enc 1 (var 0)) ≡ lambda lambda g a ((ren (add 2) s) (enc 0 (var 0))).
Proof.
intros H; rewrite !H; now simplify.
Qed.
Section Variables.
Definition F (x: nat): nat := (I__S (inl x)).
Definition G (x y z: nat): nat := I__S (inr (I__P (x, I__P (y, z)))).
Lemma disjoint_F_G x m n p: F x <> G m n p.
Proof.
intros H. unfold F, G in H; eapply injective_I__S in H. discriminate.
Qed.
Lemma F_injective x y: F x = F y -> x = y.
Proof.
intros H; unfold F in H; eapply injective_I__S in H. now injection H.
Qed.
Lemma G_injective a b c x y z: G a b c = G x y z -> a = x /\ b = y /\ c = z.
Proof.
intros H; unfold G in H; eapply injective_I__S in H. injection H as H.
apply injective_I__P in H; injection H as ? H.
apply injective_I__P in H; injection H as ? H.
intuition.
Qed.
Lemma partition_F_G:
forall h, { x | F x = h } + { '(x, y, z) | G x y z = h } .
Proof.
intros h. unfold F, G. destruct (R__S h) eqn: H1.
+ left. exists n. rewrite <-H1. now rewrite I__S_R__S.
+ right. destruct (R__P n) as [a n'] eqn: H2.
destruct (R__P n') as [b c] eqn: H3.
exists (a, b, c).
apply (f_equal I__S) in H1.
apply (f_equal I__P) in H2.
apply (f_equal I__P) in H3.
rewrite ?I__P_R__P, ?I__S_R__S in *.
now subst.
Qed.
Definition Fs E := map F (Vars__de E).
Definition Gs (E: list deq) :=
flat_map (fun e =>
match e with
| (x *ₑ y =ₑ z) => [G x y z]
| _ => nil
end) E.
Lemma Fs_in x E: x ∈ Vars__de E -> F x ∈ Fs E.
Proof.
intros; eapply in_map_iff.
exists x; intuition.
Qed.
Lemma Gs_in x y z E: (x *ₑ y =ₑ z) ∈ E -> G x y z ∈ Gs E.
Proof.
intros; eapply in_flat_map.
exists (x *ₑ y =ₑ z). intuition.
Qed.
Lemma in_Fs y E: y ∈ Fs E -> exists x, F x = y /\ x ∈ Vars__de E.
Proof.
intros H; unfold Fs in *; now eapply in_map_iff in H.
Qed.
Lemma in_Gs y E: y ∈ Gs E -> exists a b c, G a b c = y /\ (a *ₑ b =ₑ c) ∈ E.
Proof.
intros H; unfold Gs in *; eapply in_flat_map in H.
destruct H as [[]]; cbn in *; intuition.
subst. exists x; exists y0; exists z. intuition.
Qed.
Lemma F_not_in_G x E:
~ F x ∈ Gs E.
Proof. intros (a & b & c & []) % in_Gs.
eapply disjoint_F_G; eauto.
Qed.
Lemma G_not_in_F x y z E:
~ G x y z ∈ Fs E.
Proof.
intros (a & []) % in_Fs.
eapply disjoint_F_G; eauto.
Qed.
End Variables.
Arguments F : simpl never.
Arguments G : simpl never.
Arguments Fs : simpl never.
Arguments Gs : simpl never.
#[export] Hint Resolve F_not_in_G G_not_in_F : core.
Section Equations.
Implicit Types (x y z: nat).
Definition Cons s t := g s t.
Notation "s ::: t" := (Cons s t) (at level 62).
Definition Nil := a.
Definition Pair s t := g s t.
Notation "⟨ s , t ⟩" := (Pair s t) (at level 60).
Definition varEQ x: eq ag :=
(lambda lambda var (2 + F x) (Succ (var 1)), lambda lambda Succ (var (2 + F x) (var 1))).
Definition constEQ x: eq ag :=
(lambda lambda (var (2 + F x)) (var 0), lambda lambda enc 1 (var 0)).
Definition addEQ x y z: eq ag :=
(lambda lambda var (2 + F x) (var (2 + F y) (var 1)), lambda lambda var (2 + F z) (var 1)).
Definition mulEQ x y z : eq ag :=
(lambda lambda var (2 + G x y z) (⟨var (2 + F z) (var 1), var (2 + F x) (var 0)⟩ ::: Nil) (var 1) (var 0) ,
lambda lambda ⟨var 1, var 0⟩ ::: var (2 + G x y z) Nil (var (2 + F y) (var 1)) (Succ (var 0))).
Definition eqs (e: deq) : eqs ag :=
match e with
| x =ₑ 1 => [varEQ x; constEQ x]
| x +ₑ y =ₑ z => [varEQ x; varEQ y; varEQ z; addEQ x y z]
| x *ₑ y =ₑ z => [varEQ x; varEQ y; varEQ z; mulEQ x y z]
end.
Notation Eqs E := (flat_map eqs E).
Lemma in_Equations q E:
q ∈ Eqs E <-> (exists e, e ∈ E /\ q ∈ eqs e).
Proof.
eapply in_flat_map.
Qed.
End Equations.
Notation Eqs E := (flat_map eqs E).
Notation "s ::: t" := (Cons s t) (at level 62).
Notation "⟨ s , t ⟩" := (Pair s t) (at level 60).
Section Typing.
Variable (E: list deq).
Definition Gamma__deq :=
tab (fun x => if partition_F_G x then (alpha → alpha) else (alpha → alpha → alpha → alpha))
(S (Sum (Fs E) + Sum (Gs E))).
Arguments Gamma__deq: simpl never.
Lemma Gamma__deq_nth_F h:
h ∈ Fs E -> nth Gamma__deq h = Some (alpha → alpha).
Proof.
intros H. unfold Gamma__deq. rewrite tab_nth.
destruct (partition_F_G) as [[x ?]|[[[x y] z] ? ]]; subst; intuition.
eapply G_not_in_F in H as [].
eapply Sum_in in H. lia.
Qed.
Lemma Gamma__deq_nth_G h:
h ∈ Gs E -> nth Gamma__deq h = Some (alpha → alpha → alpha → alpha).
Proof.
intros H. unfold Gamma__deq. rewrite tab_nth.
destruct (partition_F_G) as [[x ?]|[[[x y] z] ? ]]; subst; intuition.
eapply F_not_in_G in H as [].
eapply Sum_in in H. lia.
Qed.
Lemma nth_Gamma__deq_F x A:
nth Gamma__deq (F x) = Some A -> A = alpha → alpha.
Proof.
intros H. eapply nth_error_Some_lt in H as H'.
unfold Gamma__deq in *. rewrite tab_nth in H; simplify in *; eauto.
destruct partition_F_G as [[]| [[[]] ?]]. congruence.
exfalso; eapply disjoint_F_G; eauto.
Qed.
Lemma nth_Gamma__deq_G x y z A:
nth Gamma__deq (G x y z) = Some A -> A = alpha → alpha → alpha → alpha.
Proof.
intros H. eapply nth_error_Some_lt in H as H'.
unfold Gamma__deq in *; simplify in *. rewrite tab_nth in H; simplify in *; eauto.
destruct partition_F_G as [[]| [[[]] ?]].
exfalso; eapply disjoint_F_G; eauto. congruence.
Qed.
Lemma Gamma__deq_content A : A ∈ Gamma__deq -> A = alpha → alpha \/ A = alpha → alpha → alpha → alpha.
Proof.
intros H; unfold Gamma__deq in *. remember (S (Sum _ + Sum _)) as n. clear Heqn.
induction n; cbn in *; intuition.
eapply in_app_iff in H; cbn in *; intuition.
destruct (partition_F_G); subst; intuition.
Qed.
Lemma ord_Gamma__deq: ord' Gamma__deq <= 2.
Proof.
unfold Gamma__deq; remember (S (Sum _ + Sum _)) as n. clear Heqn.
induction n; cbn; simplify; cbn; eauto.
rewrite IHn; simplify.
destruct (partition_F_G).
all: cbn [ord' ord alpha]; eauto.
Qed.
Lemma typing_F x:
x ∈ Vars__de E -> Gamma__deq ⊢(2) @var ag (F x) : alpha → alpha.
Proof.
intros H.
econstructor.
cbn; eauto.
now eapply Gamma__deq_nth_F, Fs_in.
Qed.
Lemma typing_G x y z:
(x *ₑ y =ₑ z) ∈ E -> Gamma__deq ⊢(2) @var ag (G x y z) : alpha → alpha → alpha → alpha.
Proof.
intros H.
econstructor.
cbn; eauto.
now eapply Gamma__deq_nth_G, Gs_in.
Qed.
Hint Resolve typing_G typing_F : core.
Ltac autotype :=
repeat match goal with
| [|- _ ⊢(2) var (?n + ?x) : _] =>
eapply ordertyping_preservation_under_renaming with (delta := add n) (s := var x)
| [|- _ ⊢(2) var (G _ _ _) : _ ]=> eapply typing_G
| [|- _ ⊢(2) var (F _) : _ ]=> eapply typing_F
| [|- _ ⊢(2) var ?n : _] => now (econstructor; cbn; eauto)
| [|- _ ⊢(2) const _ : _] => eauto
| [|- _ ⊢(2) enc _ _ : _] => eapply enc_typing
| [|- _ ⊢(2) _ : _] => econstructor
| [|- _ ⊫ add _ : _] => now intros ??
| [H: ?e ∈ E |- _ ∈ Vars__de E] => eapply Vars__de_in; [eapply H|cbn;intuition]
end.
Lemma typing_var_eq x:
x ∈ Vars__de E -> Gamma__deq ⊢₂(2) varEQ x : alpha → alpha → alpha.
Proof.
intros; unfold varEQ; split; cbn [fst snd].
all: autotype; eauto.
Qed.
Lemma typing_const x:
x =ₑ 1 ∈ E -> Gamma__deq ⊢₂(2) constEQ x : alpha → alpha → alpha.
Proof.
intros; unfold constEQ; split; cbn [fst snd]; autotype.
Qed.
Lemma typing_add x y z:
x +ₑ y =ₑ z ∈ E -> Gamma__deq ⊢₂(2) addEQ x y z : alpha → alpha → alpha.
Proof.
intros; unfold addEQ; split; cbn [fst snd]; autotype.
Qed.
Lemma typing_mul x y z:
x *ₑ y =ₑ z ∈ E -> Gamma__deq ⊢₂(2) mulEQ x y z : alpha → alpha → alpha.
Proof.
intros; unfold mulEQ; split; cbn [fst snd]; autotype; eauto.
Qed.
Lemma typing_equations q e:
e ∈ E -> q ∈ eqs e -> Gamma__deq ⊢₂(2) q : alpha → alpha → alpha.
Proof.
intros H H1; destruct e; cbn in H1; intuition; subst;
eauto using typing_const, typing_add, typing_mul.
all: eapply typing_var_eq; autotype.
Qed.
End Typing.
Global Program Instance H10_to_SOU (E: list deq): ordsysuni ag 2 :=
{
Gamma₀' := Gamma__deq E;
E₀' := Eqs E;
L₀' := repeat (alpha → alpha → alpha) (length (Eqs E));
H₀' := _;
}.
Next Obligation.
eapply ordertyping_combine; eapply repeated_ordertyping;
unfold left_side, right_side; simplify; eauto 1.
all: intros ? ?; mapinj; eapply in_flat_map in H1 as []; intuition.
all: eapply typing_equations; eauto.
Qed.
Require Import RelationClasses Morphisms List Lia Init.Nat Setoid.
From Undecidability.HOU Require Import calculus.calculus second_order.diophantine_equations
systemunification nth_order_unification.
Import ListNotations.
Set Default Proof Using "Type".
Definition ag : Const :=
{|
const_type := option (option False);
ctype := fun o =>
match o with
| None => alpha → alpha → alpha
| Some None => alpha
| Some (Some f) => match f with end
end;
|}.
Notation g := (@const ag None).
Notation a := (@const ag (Some None)).
Lemma typing_a Gamma: Gamma ⊢(2) a : alpha.
Proof. econstructor; cbn; eauto. Qed.
Lemma typing_g Gamma: Gamma ⊢(2) g : alpha → alpha → alpha.
Proof. econstructor; cbn; eauto. Qed.
#[export] Hint Resolve typing_a typing_g : core.
Section Linearization.
Implicit Types (S: list (exp ag)).
Definition lin S t := AppL (map (app g) S) t.
Lemma lin_nil t: lin nil t = t.
Proof. reflexivity. Qed.
Lemma lin_cons s S t:
lin (s :: S) t = g s (lin S t).
Proof. reflexivity. Qed.
Lemma lin_app S1 S2 t:
lin (S1 ++ S2) t = lin S1 (lin S2 t).
Proof. unfold lin; simplify; now rewrite AppL_app. Qed.
Hint Rewrite lin_nil lin_cons lin_app : simplify.
Lemma lin_typing Gamma S t:
(Gamma ⊢₊(2) S : repeat alpha (length S)) ->
(Gamma ⊢(2) t : alpha) ->
Gamma ⊢(2) lin S t : alpha.
Proof.
intros ? ?. induction S as [|s S IH]; simplify; [eauto|]. inv H.
econstructor; cbn; eauto.
Qed.
Lemma lin_ren delta S t:
ren delta (lin S t) = lin (renL delta S) (ren delta t).
Proof. unfold lin; asimpl; now rewrite !map_map. Qed.
Lemma lin_subst sigma S t:
sigma • lin S t = lin (sigma •₊ S) (sigma • t).
Proof. unfold lin; asimpl; now rewrite !map_map. Qed.
Hint Rewrite lin_ren lin_subst : asimpl.
Lemma lin_injective S T s t:
length S = length T -> lin S s = lin T t -> S = T /\ s = t.
Proof.
induction S in T |-*; destruct T; try discriminate; simplify in *; eauto.
intros; edestruct IHS.
all: injection H as H; eauto.
all: injection H0; intuition; subst; intuition.
Qed.
Lemma largest_lin s:
exists S t, s = lin S t /\ forall s' t', t <> g s' t'.
Proof.
edestruct (AppL_largest s (P := fun (s: exp ag) => match s with app (const None) s => True | _ => False end))
as (S & t & H1 & H2 & H3).
intros [| | | [| [] | | ]]. 1 - 8: firstorder. subst.
enough (exists S', S = map (app g) S') as [S' ->].
exists S'. exists t. intuition. eapply H3; cbn; eauto; cbn; eauto.
clear H3. induction S. now (exists nil).
specialize (H1 a) as H2; mp H2; intuition; destruct a as [| | | [| [] | | ]]; intuition.
edestruct IHS as [S']; intros. eapply H1; intuition. subst. now (exists (a1 :: S')).
Qed.
Lemma lin_normal S t:
(forall s, s ∈ S -> normal s) -> normal t -> normal (lin S t).
Proof.
intros; induction S; cbn; [eauto|].
repeat apply normal_app_intro; eauto.
Qed.
End Linearization.
Global Hint Rewrite lin_ren lin_subst : asimpl.
Global Hint Rewrite lin_nil lin_cons lin_app : simplify.
Section Encoding.
Notation Succ := (g a).
Definition enc n s := lin (repeat a n) s.
Definition encodes s n := forall t delta, (ren delta s) t ≡ enc n t.
Arguments enc : simpl never.
Section enc_equations.
Lemma enc_zero t: enc 0 t = t.
Proof. reflexivity. Qed.
Hint Rewrite enc_zero : simplify.
Lemma enc_succ n t: enc (S n) t = Succ (enc n t).
Proof. reflexivity. Qed.
Hint Rewrite enc_succ : simplify.
Lemma enc_succ_out n t: enc n (Succ t) = Succ (enc n t).
Proof. induction n; simplify; congruence. Qed.
Hint Rewrite enc_succ_out : simplify.
Lemma enc_app n m t:
enc (n + m) t = enc n (enc m t).
Proof. induction n; cbn; simplify; congruence. Qed.
Hint Rewrite enc_app : simplify.
End enc_equations.
Hint Rewrite enc_app enc_succ_out enc_succ enc_zero : simplify.
Lemma enc_ren delta n s:
ren delta (enc n s) = enc n (ren delta s).
Proof.
unfold enc; asimpl; now rewrite repeated_map.
Qed.
Lemma enc_subst sigma n s:
sigma • enc n s = enc n (sigma • s).
Proof.
unfold enc; asimpl; now rewrite repeated_map.
Qed.
Hint Rewrite enc_ren enc_subst : asimpl.
Lemma enc_normal n s:
normal s -> normal (enc n s).
Proof.
intros; induction n; simplify.
- eauto.
- eapply normal_app_intro; [|eapply normal_app_intro|]; eauto.
Qed.
Hint Resolve enc_normal : core.
Lemma enc_injective n m s t:
isAtom s -> isAtom t -> enc n s ≡ enc m t -> n = m /\ s = t.
Proof.
induction n in m |-*; simplify in *; destruct m; simplify in *; intros.
- intuition. destruct s, t; cbn in *; intuition; try Discriminate; Injection H1; congruence.
- destruct s; cbn in *; intuition; Discriminate.
- destruct t; cbn in *; intuition; Discriminate.
- Injection H1. eapply IHn in H3; eauto.
intuition.
Qed.
Lemma enc_typing Gamma s n:
(Gamma ⊢(2) s : alpha) ->
Gamma ⊢(2) enc n s : alpha.
Proof.
intros; unfold enc.
eapply lin_typing; eauto.
eapply repeated_ordertyping; [|eauto].
intros ? <- % repeated_in.
econstructor; eauto.
Qed.
Global Instance enc_equiv: Proper (Logic.eq ++> equiv step ++> equiv step) enc.
Proof.
intros ?? -> ??; unfold enc, lin; now intros ->.
Qed.
Lemma dec_enc_eq :
forall s, { n | s = enc n a } + ({ n | s = enc n a } -> False).
Proof.
induction s as [| [[[]|]|] | | s1 IH1 s3 IH3].
all: try (right; intros [[|n] ]; cbn; discriminate).
- left. exists 0. reflexivity.
- destruct IH3 as [[n]|]; subst.
+ destruct s1 as [| | | s1 s2 ].
all: try (right; intros [[|n'] ]; cbn; discriminate).
destruct s1 as [| [[]|] | | ].
all: try (right; intros [[|n'] ]; cbn; discriminate).
destruct s2 as [| [[]|] | | ].
all: try (right; intros [[|n'] ]; cbn; discriminate).
left. exists (S n). reflexivity.
+ right. intros [n H].
destruct n; try discriminate; cbn in *; injection H.
intros; eapply f; subst; now (exists n).
Qed.
Lemma dec_enc:
forall s, normal s -> { n | s a ≡ enc n a } + ({ n | s a ≡ enc n a } -> False).
Proof.
intros s N. specialize (@red_fun_rho _ (@step ag) (@par ag) rho) as f.
do 4 mp f; try typeclasses eauto; eauto.
assert (s a ▷ rho (s a)).
- eapply id in f as g. destruct g as [H1 H2].
split; [eauto|]. destruct s; cbn.
+ eapply normal_app_intro; eauto.
+ eapply normal_app_intro; eauto.
+ eapply normal_subst.
1 - 2: intros []; cbn; eauto.
enough (rho s = s) as -> by eauto using normal_lam_elim.
eapply red_fun_fp; eauto using normal_lam_elim.
+ eapply head_atom in N as isA; [|eauto].
assert (rho s1 = s1) as -> by (eapply red_fun_fp; eauto using normal_app_l, normal_app_r).
assert (rho s2 = s2) as -> by (eapply red_fun_fp; eauto using normal_app_l, normal_app_r).
destruct s1; cbn in isA; intuition.
- destruct (dec_enc_eq (rho (s a))) as [[n H1]|H1].
+ left. exists n. rewrite H1 in H. eapply equiv_join. rewrite H. all: eauto.
+ right. intros [n H2]. eapply H1. exists n.
eapply equiv_unique_normal_forms; eauto. 2: eapply H. rewrite <-H2.
symmetry. eapply equiv_join. rewrite H. all: eauto.
Qed.
End Encoding.
#[export] Hint Resolve enc_normal : core.
Global Hint Rewrite enc_zero enc_succ enc_app enc_succ_out: simplify.
Global Hint Rewrite enc_ren enc_subst: asimpl.
Arguments enc : simpl never.
Notation Succ := (g a).
Lemma normal_forms_encodes s:
normal s -> lambda lambda (ren (add 2) s) (enc 1 (var 1)) ≡ lambda lambda Succ ((ren (add 2) s) (var 1)) ->
exists n, encodes s n.
Proof.
remember (add 2) as delta.
cbn; intros H EQ % equiv_lam_elim % equiv_lam_elim; destruct s; cbn in EQ.
- Injection EQ; Discriminate.
- Injection EQ; Discriminate.
- eapply equiv_reduce in EQ.
2, 3: dostep; asimpl; reflexivity.
eapply normal_lam_elim in H.
enough (exists n : nat, forall t delta, t .: delta >> var • s ≡ enc n t) as [n H'] by
(exists n; intros t delta'; asimpl; rewrite stepBeta; asimpl; eauto).
induction s as [[] | | |]; unfold funcomp in EQ; cbn in EQ.
+ now (exists 0).
+ Discriminate.
+ Discriminate.
+ Discriminate.
+ eapply head_atom in H as H'; cbn; intuition.
eapply equiv_app_elim in EQ as [EQ1 EQ2]; cbn; intuition.
2: eapply atom_head_lifting; eauto; intros []; cbn; intuition.
enough (s1 = g a).
* subst. cbn in EQ2.
eapply IHs2 in EQ2. 2: eauto using normal_app_r.
destruct EQ2. subst.
exists (S x). intros t delta; cbn; simplify; now rewrite H0.
* destruct s1 as [[] | | | t1 t2]; simplify in EQ1; cbn in *.
1 - 4: try Injection EQ1; Discriminate.
assert (isAtom (head (g a (var 1) .: delta >> var • t1)))
by (eapply atom_head_lifting; eauto; intros []; cbn; intuition).
Injection EQ1.
assert (isAtom (head t2)).
{ eapply head_atom. eauto using normal_app_r, normal_app_l.
intros ?; destruct t2; cbn in H2; intuition; Discriminate.
}
assert (isAtom (head (g a (var 1) .: delta >> var • t2)))
by (eapply atom_head_lifting; eauto; intros []; cbn; intuition).
destruct t1; cbn in *; try Discriminate.
destruct f; cbn in *; Discriminate.
destruct t2; cbn in *; try Discriminate.
destruct f; cbn in *; Discriminate.
Injection H1; subst.
Injection H2; subst.
reflexivity.
- eapply normal_ren with (delta := delta) in H.
eapply head_atom in H; eauto. cbn in EQ.
Injection EQ. Injection H0.
unshelve eapply ren_equiv_proper in H2;
[exact (pred >> pred)|exact (pred >> pred)|eauto..]; asimpl in H2.
unshelve eapply ren_equiv_proper in H3;
[exact (pred >> pred)|exact (pred >> pred)|eauto..]; asimpl in H3.
exists 1. intros t delta'; simplify. subst delta. asimpl in H3. asimpl in H2.
now rewrite H2, H3.
Qed.
Lemma encodes_characeristic s n:
encodes s n -> lambda lambda (ren (add 2) s) (enc 1 (var 0)) ≡ lambda lambda g a ((ren (add 2) s) (enc 0 (var 0))).
Proof.
intros H; rewrite !H; now simplify.
Qed.
Section Variables.
Definition F (x: nat): nat := (I__S (inl x)).
Definition G (x y z: nat): nat := I__S (inr (I__P (x, I__P (y, z)))).
Lemma disjoint_F_G x m n p: F x <> G m n p.
Proof.
intros H. unfold F, G in H; eapply injective_I__S in H. discriminate.
Qed.
Lemma F_injective x y: F x = F y -> x = y.
Proof.
intros H; unfold F in H; eapply injective_I__S in H. now injection H.
Qed.
Lemma G_injective a b c x y z: G a b c = G x y z -> a = x /\ b = y /\ c = z.
Proof.
intros H; unfold G in H; eapply injective_I__S in H. injection H as H.
apply injective_I__P in H; injection H as ? H.
apply injective_I__P in H; injection H as ? H.
intuition.
Qed.
Lemma partition_F_G:
forall h, { x | F x = h } + { '(x, y, z) | G x y z = h } .
Proof.
intros h. unfold F, G. destruct (R__S h) eqn: H1.
+ left. exists n. rewrite <-H1. now rewrite I__S_R__S.
+ right. destruct (R__P n) as [a n'] eqn: H2.
destruct (R__P n') as [b c] eqn: H3.
exists (a, b, c).
apply (f_equal I__S) in H1.
apply (f_equal I__P) in H2.
apply (f_equal I__P) in H3.
rewrite ?I__P_R__P, ?I__S_R__S in *.
now subst.
Qed.
Definition Fs E := map F (Vars__de E).
Definition Gs (E: list deq) :=
flat_map (fun e =>
match e with
| (x *ₑ y =ₑ z) => [G x y z]
| _ => nil
end) E.
Lemma Fs_in x E: x ∈ Vars__de E -> F x ∈ Fs E.
Proof.
intros; eapply in_map_iff.
exists x; intuition.
Qed.
Lemma Gs_in x y z E: (x *ₑ y =ₑ z) ∈ E -> G x y z ∈ Gs E.
Proof.
intros; eapply in_flat_map.
exists (x *ₑ y =ₑ z). intuition.
Qed.
Lemma in_Fs y E: y ∈ Fs E -> exists x, F x = y /\ x ∈ Vars__de E.
Proof.
intros H; unfold Fs in *; now eapply in_map_iff in H.
Qed.
Lemma in_Gs y E: y ∈ Gs E -> exists a b c, G a b c = y /\ (a *ₑ b =ₑ c) ∈ E.
Proof.
intros H; unfold Gs in *; eapply in_flat_map in H.
destruct H as [[]]; cbn in *; intuition.
subst. exists x; exists y0; exists z. intuition.
Qed.
Lemma F_not_in_G x E:
~ F x ∈ Gs E.
Proof. intros (a & b & c & []) % in_Gs.
eapply disjoint_F_G; eauto.
Qed.
Lemma G_not_in_F x y z E:
~ G x y z ∈ Fs E.
Proof.
intros (a & []) % in_Fs.
eapply disjoint_F_G; eauto.
Qed.
End Variables.
Arguments F : simpl never.
Arguments G : simpl never.
Arguments Fs : simpl never.
Arguments Gs : simpl never.
#[export] Hint Resolve F_not_in_G G_not_in_F : core.
Section Equations.
Implicit Types (x y z: nat).
Definition Cons s t := g s t.
Notation "s ::: t" := (Cons s t) (at level 62).
Definition Nil := a.
Definition Pair s t := g s t.
Notation "⟨ s , t ⟩" := (Pair s t) (at level 60).
Definition varEQ x: eq ag :=
(lambda lambda var (2 + F x) (Succ (var 1)), lambda lambda Succ (var (2 + F x) (var 1))).
Definition constEQ x: eq ag :=
(lambda lambda (var (2 + F x)) (var 0), lambda lambda enc 1 (var 0)).
Definition addEQ x y z: eq ag :=
(lambda lambda var (2 + F x) (var (2 + F y) (var 1)), lambda lambda var (2 + F z) (var 1)).
Definition mulEQ x y z : eq ag :=
(lambda lambda var (2 + G x y z) (⟨var (2 + F z) (var 1), var (2 + F x) (var 0)⟩ ::: Nil) (var 1) (var 0) ,
lambda lambda ⟨var 1, var 0⟩ ::: var (2 + G x y z) Nil (var (2 + F y) (var 1)) (Succ (var 0))).
Definition eqs (e: deq) : eqs ag :=
match e with
| x =ₑ 1 => [varEQ x; constEQ x]
| x +ₑ y =ₑ z => [varEQ x; varEQ y; varEQ z; addEQ x y z]
| x *ₑ y =ₑ z => [varEQ x; varEQ y; varEQ z; mulEQ x y z]
end.
Notation Eqs E := (flat_map eqs E).
Lemma in_Equations q E:
q ∈ Eqs E <-> (exists e, e ∈ E /\ q ∈ eqs e).
Proof.
eapply in_flat_map.
Qed.
End Equations.
Notation Eqs E := (flat_map eqs E).
Notation "s ::: t" := (Cons s t) (at level 62).
Notation "⟨ s , t ⟩" := (Pair s t) (at level 60).
Section Typing.
Variable (E: list deq).
Definition Gamma__deq :=
tab (fun x => if partition_F_G x then (alpha → alpha) else (alpha → alpha → alpha → alpha))
(S (Sum (Fs E) + Sum (Gs E))).
Arguments Gamma__deq: simpl never.
Lemma Gamma__deq_nth_F h:
h ∈ Fs E -> nth Gamma__deq h = Some (alpha → alpha).
Proof.
intros H. unfold Gamma__deq. rewrite tab_nth.
destruct (partition_F_G) as [[x ?]|[[[x y] z] ? ]]; subst; intuition.
eapply G_not_in_F in H as [].
eapply Sum_in in H. lia.
Qed.
Lemma Gamma__deq_nth_G h:
h ∈ Gs E -> nth Gamma__deq h = Some (alpha → alpha → alpha → alpha).
Proof.
intros H. unfold Gamma__deq. rewrite tab_nth.
destruct (partition_F_G) as [[x ?]|[[[x y] z] ? ]]; subst; intuition.
eapply F_not_in_G in H as [].
eapply Sum_in in H. lia.
Qed.
Lemma nth_Gamma__deq_F x A:
nth Gamma__deq (F x) = Some A -> A = alpha → alpha.
Proof.
intros H. eapply nth_error_Some_lt in H as H'.
unfold Gamma__deq in *. rewrite tab_nth in H; simplify in *; eauto.
destruct partition_F_G as [[]| [[[]] ?]]. congruence.
exfalso; eapply disjoint_F_G; eauto.
Qed.
Lemma nth_Gamma__deq_G x y z A:
nth Gamma__deq (G x y z) = Some A -> A = alpha → alpha → alpha → alpha.
Proof.
intros H. eapply nth_error_Some_lt in H as H'.
unfold Gamma__deq in *; simplify in *. rewrite tab_nth in H; simplify in *; eauto.
destruct partition_F_G as [[]| [[[]] ?]].
exfalso; eapply disjoint_F_G; eauto. congruence.
Qed.
Lemma Gamma__deq_content A : A ∈ Gamma__deq -> A = alpha → alpha \/ A = alpha → alpha → alpha → alpha.
Proof.
intros H; unfold Gamma__deq in *. remember (S (Sum _ + Sum _)) as n. clear Heqn.
induction n; cbn in *; intuition.
eapply in_app_iff in H; cbn in *; intuition.
destruct (partition_F_G); subst; intuition.
Qed.
Lemma ord_Gamma__deq: ord' Gamma__deq <= 2.
Proof.
unfold Gamma__deq; remember (S (Sum _ + Sum _)) as n. clear Heqn.
induction n; cbn; simplify; cbn; eauto.
rewrite IHn; simplify.
destruct (partition_F_G).
all: cbn [ord' ord alpha]; eauto.
Qed.
Lemma typing_F x:
x ∈ Vars__de E -> Gamma__deq ⊢(2) @var ag (F x) : alpha → alpha.
Proof.
intros H.
econstructor.
cbn; eauto.
now eapply Gamma__deq_nth_F, Fs_in.
Qed.
Lemma typing_G x y z:
(x *ₑ y =ₑ z) ∈ E -> Gamma__deq ⊢(2) @var ag (G x y z) : alpha → alpha → alpha → alpha.
Proof.
intros H.
econstructor.
cbn; eauto.
now eapply Gamma__deq_nth_G, Gs_in.
Qed.
Hint Resolve typing_G typing_F : core.
Ltac autotype :=
repeat match goal with
| [|- _ ⊢(2) var (?n + ?x) : _] =>
eapply ordertyping_preservation_under_renaming with (delta := add n) (s := var x)
| [|- _ ⊢(2) var (G _ _ _) : _ ]=> eapply typing_G
| [|- _ ⊢(2) var (F _) : _ ]=> eapply typing_F
| [|- _ ⊢(2) var ?n : _] => now (econstructor; cbn; eauto)
| [|- _ ⊢(2) const _ : _] => eauto
| [|- _ ⊢(2) enc _ _ : _] => eapply enc_typing
| [|- _ ⊢(2) _ : _] => econstructor
| [|- _ ⊫ add _ : _] => now intros ??
| [H: ?e ∈ E |- _ ∈ Vars__de E] => eapply Vars__de_in; [eapply H|cbn;intuition]
end.
Lemma typing_var_eq x:
x ∈ Vars__de E -> Gamma__deq ⊢₂(2) varEQ x : alpha → alpha → alpha.
Proof.
intros; unfold varEQ; split; cbn [fst snd].
all: autotype; eauto.
Qed.
Lemma typing_const x:
x =ₑ 1 ∈ E -> Gamma__deq ⊢₂(2) constEQ x : alpha → alpha → alpha.
Proof.
intros; unfold constEQ; split; cbn [fst snd]; autotype.
Qed.
Lemma typing_add x y z:
x +ₑ y =ₑ z ∈ E -> Gamma__deq ⊢₂(2) addEQ x y z : alpha → alpha → alpha.
Proof.
intros; unfold addEQ; split; cbn [fst snd]; autotype.
Qed.
Lemma typing_mul x y z:
x *ₑ y =ₑ z ∈ E -> Gamma__deq ⊢₂(2) mulEQ x y z : alpha → alpha → alpha.
Proof.
intros; unfold mulEQ; split; cbn [fst snd]; autotype; eauto.
Qed.
Lemma typing_equations q e:
e ∈ E -> q ∈ eqs e -> Gamma__deq ⊢₂(2) q : alpha → alpha → alpha.
Proof.
intros H H1; destruct e; cbn in H1; intuition; subst;
eauto using typing_const, typing_add, typing_mul.
all: eapply typing_var_eq; autotype.
Qed.
End Typing.
Global Program Instance H10_to_SOU (E: list deq): ordsysuni ag 2 :=
{
Gamma₀' := Gamma__deq E;
E₀' := Eqs E;
L₀' := repeat (alpha → alpha → alpha) (length (Eqs E));
H₀' := _;
}.
Next Obligation.
eapply ordertyping_combine; eapply repeated_ordertyping;
unfold left_side, right_side; simplify; eauto 1.
all: intros ? ?; mapinj; eapply in_flat_map in H1 as []; intuition.
all: eapply typing_equations; eauto.
Qed.