(** * Skelet #1 *)
(** Following https://www.sligocki.com/2023/03/13/skelet-1-infinite.html *)
Set Warnings "-abstract-large-number".
Set Default Goal Selector "!".
Definition tm : TM := fun '(q, s) =>
match q, s with
| A, 0 => Some (1, R, B)  | A, 1 => Some (1, R, D)
| B, 0 => Some (1, L, C)  | B, 1 => Some (0, R, C)
| C, 0 => Some (1, R, A)  | C, 1 => Some (1, L, D)
| D, 0 => Some (0, R, E)  | D, 1 => Some (0, L, B)
| E, 0 => None            | E, 1 => Some (1, R, C)
end.
Notation "c --> c'" := (c -[ tm ]-> c')   (at level 40).
Notation "c -->* c'" := (c -[ tm ]->* c') (at level 40).
Notation "c -->+ c'" := (c -[ tm ]->+ c') (at level 40).
Notation "l <| r" := (l <{{C}} 1 >> 0 >> r)  (at level 30).
Notation "l |> r" := (l {{A}}> r)  (at level 30).
Fixpoint run (n : nat) :=
match n with
| O => [0]
| S n => run n <: 1
end.
Definition x  := run 2 <+ run 2.
Definition Dl := run 2 <+ run 1.
Definition Dr := run 2 +> run 1.
Definition C0 := run 2 <+ run 3 <+ run 2.
Definition C1 := run 2 <+ run 0 <+ run 1.
Definition C2 := run 4 <+ run 2.
Definition C3 := run 1 <+ run 1.
Notation C := C3.
Definition R := const 0.
Definition L := const 0.
Definition P  := run 2.
Definition F0 := run 4 <+ run 3 <+ run 2.
Definition F1 := run 4 <+ run 0 <+ run 1.
Definition F2 := run 6 <+ run 2.
Definition F3 := run 3 <+ run 1.
Definition G0 := run 2 <+ run 3 <+ run 3 <+ run 2.
Definition G1 := run 2 <+ run 3 <+ run 0 <+ run 1.
Definition G2 := run 2 <+ run 5 <+ run 2.
Definition Fl := C2 <+ x^^7640 <+ Dl <+ x^^10344.
Definition Gl :=
x^^300 <+ Dl <+ x^^30826 <+ Dl <+ x^^72142 <+ Dl <+
x^^3076 <+ Dl <+ x^^1538 <+ Dl.
Definition Gr :=
x^^300 +> Dr +> x^^30826 +> Dr +> x^^72142 +> Dr +>
x^^3076 +> Dr +> x^^1538 +> Dr.
Definition Hl :=
C1 <+ Dl <+ x^^299 <+ C1 <+ Dl <+ x^^30825 <+
C1 <+ Dl <+ x^^72141 <+ C1 <+ Dl <+ x^^3075 <+
C1 <+ Dl <+ x^^1537.
Inductive lsym :=
| l_xs (n : positive)
| l_D
| l_P
| l_C0 | l_C1 | l_C2 | l_C3
| l_F0 | l_F1 | l_F2 | l_F3
| l_G0 | l_G1 | l_G2
| l_Fs (n : positive)
| l_Gs (n : positive)
| l_Hs (n : positive).
Inductive rsym :=
| r_xs (n : positive)
| r_D
| r_C
| r_P
| r_Gs (n : positive).
Notation ltape := (list lsym).
Notation rtape := (list rsym).
Definition F := [l_xs 10344; l_D; l_xs 7640; l_C2].
Definition G := [r_xs 300; r_D; r_xs 30826; r_D; r_xs 72142; r_D;
r_xs 3076; r_D; r_xs 1538; r_D].
Definition J := [l_D; l_C2; l_xs 95; l_C0;
l_xs 7713; l_D; l_D; l_xs 1866; l_C1;
l_xs 13231; l_D; l_xs 6197; l_C3;
l_xs 11066; l_D; l_xs 7279; l_C0;
l_xs 10524; l_D; l_xs 7550; l_C2;
l_xs 10389; l_D; l_xs 7618; l_C1;
l_xs 10355; l_D; l_xs 7635; l_C3;
l_xs 10347; l_D; l_xs 7639; l_C3;
l_xs 10345; l_D; l_xs 7640; l_C1].
Definition K : rtape :=
[r_xs 7639; r_D; r_xs 10347; r_C;
r_xs 7635; r_D; r_xs 10355; r_C;
r_xs 7619; r_D; r_xs 10387; r_C;
r_xs 7555; r_D; r_xs 10515; r_C;
r_xs 7299; r_D; r_xs 11027; r_C;
r_xs 6275; r_D; r_xs 13075; r_C;
r_xs 2179; r_D; r_D; r_xs 7088; r_C;
r_xs 1; r_C; r_xs 3849; r_P].
Definition uni_P : positive := 53946.
Definition uni_T : positive := 4 * uni_P - 5.
Definition eqb_l (a b : lsym) : bool :=
match a,b with
| l_xs n1,l_xs n2 => Pos.eqb n1 n2
| l_D,l_D
| l_P,l_P
| l_C0,l_C0 | l_C1,l_C1 | l_C2,l_C2 | l_C3,l_C3
| l_F0,l_F0 | l_F1,l_F1 | l_F2,l_F2 | l_F3,l_F3
| l_G0,l_G0 | l_G1,l_G1 | l_G2,l_G2 => true
| l_Fs n1,l_Fs n2 => Pos.eqb n1 n2
| l_Gs n1,l_Gs n2 => Pos.eqb n1 n2
| l_Hs n1,l_Hs n2 => Pos.eqb n1 n2
| _,_ => false
end.
Definition eqb_r (a b : rsym) : bool :=
match a,b with
| r_xs n1,r_xs n2 => Pos.eqb n1 n2
| r_D,r_D => true
| r_C,r_C => true
| r_P,r_P => true
| r_Gs n1,r_Gs n2 => Pos.eqb n1 n2
| _,_ => false
end.
Fixpoint eqb_rtape (xs ys : rtape): bool :=
match xs,ys with
| xh::xt,yh::yt => if eqb_r xh yh then eqb_rtape xt yt else false
| nil,nil => true
| _,_ => false
end.
Notation left := TM.L.
Notation right := TM.R.
Notation conf := (dir * ltape * rtape)%type.
Fixpoint lift_right (t : rtape) : side :=
match t with
| [] => R
| r_xs n :: t => x^^(Pos.to_nat n) *> lift_right t
| r_D :: t => Dr *> lift_right t
| r_C :: t => C *> lift_right t
| r_P :: t => P *> lift_right t
| r_Gs n :: t => Gr^^(Pos.to_nat n) *> lift_right t
end.
Fixpoint lift_left (t : ltape) : side :=
match t with
| [] => L
| l_xs n :: t => lift_left t <* x^^(Pos.to_nat n)
| l_D :: t => lift_left t <* Dl
| l_P :: t => lift_left t <* P
| l_C0 :: t => lift_left t <* C0
| l_C1 :: t => lift_left t <* C1
| l_C2 :: t => lift_left t <* C2
| l_C3 :: t => lift_left t <* C3
| l_F0 :: t => lift_left t <* F0
| l_F1 :: t => lift_left t <* F1
| l_F2 :: t => lift_left t <* F2
| l_F3 :: t => lift_left t <* F3
| l_G0 :: t => lift_left t <* G0
| l_G1 :: t => lift_left t <* G1
| l_G2 :: t => lift_left t <* G2
| l_Fs n :: t => lift_left t <* Fl^^(Pos.to_nat n)
| l_Gs n :: t => lift_left t <* Gl^^(Pos.to_nat n)
| l_Hs n :: t => lift_left t <* Hl^^(Pos.to_nat n)
end.
Definition lift (c : conf) : Q * tape :=
match c with
| (left,  l, r) => lift_left l <| lift_right r
| (right, l, r) => lift_left l |> lift_right r
end.
Definition decr (n : positive) : N :=
N.pred (N.pos n).

Lemma decr_nat : forall n, N.to_nat (decr (Pos.of_succ_nat n)) = n.