Require Import wstype ptype.
Require Import Lia Arith Utils.Various_utils Program.Equality.
Section polyadic.
Context {w:nat}.
Fixpoint iterShift {m} (n:nat) (t: fin m) : fin (n+m) := match n with
| 0 => t
| S n0 => ↑(iterShift n0 t)
end.
Fixpoint mkAll {n m} (v : Vector.t (wstype.type m) n) (b : wstype.type (m+w)) {struct v} : n<=w -> wstype.type ((w-n)+m).
Proof. intro. destruct v.
-rewrite Nat.sub_0_r,Nat.add_comm. exact b.
-apply wstype.all. exact (wstype.ren_type (iterShift (w-S n)) h).
assert (S (w - S n + m)=w-n+m) as -> by lia. eapply (mkAll _ _ v b). lia.
Defined.
Fixpoint encode {n : nat} (t : @ptype.type w n) : wstype.type (w*n).
Proof. destruct t.
-eapply wstype.var_type,nat2fin,(fins2nat_lt f0 f).
-rewrite <- plus_O_n,(minus_diag_reverse w). apply (mkAll (Vector.map (encode _) t)). rewrite mult_n_Sm. exact (encode _ t0). lia.
Defined.
Notation "⟦ t ⟧" := (encode t).
Definition encode_ren {n m : nat} (ξ : fin n -> fin m) : fin (w*n) -> fin (w*m).
Proof. intro xi. destruct (fin2nat xi) as [j Hj]. destruct (nat2fins Hj) as [i x]. apply ξ in x.
eapply nat2fin. apply (fins2nat_lt i x).
Defined.
Notation "« r »" := (encode_ren r).
Fact ext_ren (n m:nat) (t : wstype.type n) (ξ ξ' : fin n -> fin m) (Hx : forall x, ξ x = ξ' x) :
wstype.ren_type ξ t = wstype.ren_type ξ' t.
Proof. now apply extRen_type.
Qed.
Theorem encoding_ren {n m : nat} (ξ : fin n -> fin m) (t : @ptype.type w n) :
⟦ ptype.ren_type ξ t ⟧ = wstype.ren_type «ξ» ⟦t⟧.
Proof. revert m ξ. induction t; intros.
-simpl. unfold encode_ren. destruct (fin2nat (nat2fin (fins2nat_lt f0 f))) eqn:H.
eapply (ap (@proj1_sig _ _)) in H. rewrite f2n_n2f in H. simpl in H.
revert l. rewrite <- H. intro. now rewrite n2fs_unfold.
-simpl ren_type. unfold encode. apply utype.congr_all. apply IHt1. rewrite IHt2. eapply ext_ren.
intros. destruct x. simpl. unfold encode_ren. destruct (le_lt_dec (S ntype) 0); now simpl.
simpl. unfold unscoped.funcomp. unfold encode_ren. destruct (le_lt_dec ntype x). lia.
destruct (le_lt_dec (S ntype) (S x)). lia. simpl.
now destruct (fin2nat (ξ (nat2fin l))).
Qed.
Definition encode_subst {n m : nat} (θ: fin n -> fin w -> @ptype.type w m) : fin (w*n) -> wstype.type (w*m).
Proof. intro ix. destruct (fin2nat ix) as [j Hj]. destruct (nat2fins Hj) as [i x].
exact ⟦ θ x i ⟧.
Defined.
Notation "[| s |]" := (encode_subst s).
Fact ext_subst (n m:nat) (t : wstype.type n) (θ θ' : fin n -> wstype.type m) (Hx : forall x, θ x = θ' x) :
wstype.subst_type θ t = wstype.subst_type θ' t.
Proof. now apply ext_type.
Qed.
Theorem encoding_subst {n m : nat} (θ: fin n -> fin w -> @ptype.type w m) (t : @ptype.type w n) :
⟦ ptype.subst_type θ t ⟧ = wstype.subst_type [|θ|] ⟦t⟧.
Proof. revert m θ. induction t; intros; simpl.
-unfold encode_subst. destruct (fin2nat (nat2fin (fins2nat_lt f0 f))) eqn:H.
eapply (ap (@proj1_sig _ _)) in H. rewrite f2n_n2f in H. simpl in H.
revert l. rewrite <- H. intro. now rewrite n2fs_unfold.
-simpl subst_type. unfold encode. destruct (le_lt_dec ntype x). lia.
destruct (le_lt_dec (S ntype) (S x)). lia. simpl.
unfold funcomp. rewrite encoding_ren. apply ext_ren. intros.
unfold encode_ren. destruct (le_lt_dec m x0). lia. simpl.
destruct (fin2nat (nat2fin l1)) eqn:Hf2n. f_equal. auto. rewrite <- (@f2n_n2f _ _ l1).
now rewrite Hf2n.
Qed.
End polyadic.