Section MM2_CM1.
Variable (P: list mm2_instr). (* MM2 program *)
Variables (a0 b0: nat). (* MM2 initial counters *)
(* encode start counters *)
Definition encode_init : list CM1.Instruction :=
(map (fun i => (1+i, 0)) (seq 0 (a0 + b0))) ++ (* a0+b0 times 2/1 *)
(map (fun i => (1+i, 1)) (seq (a0 + b0) b0)). (* b0 times 3/2 *)
(* instruction index map *)
Definition fs (i: nat) : CM1.State :=
if i is S i then i*6 + a0 + b0 + b0 else (length P)*6 + a0 + b0 + b0.
(* encode instruction mmi at position i using index map fs for current cm1 state p *)
Definition encode_instruction (mmi: mm2_instr) (i: nat) : list CM1.Instruction :=
let p := fs i in
match mmi with
| mm2_inc_a =>
[(fs (1+i), 0)] ++ (* 2/1, goto i+1 *)
[(0, 0); (0, 0); (0, 0); (0, 0); (0, 0)] (* filler *)
| mm2_inc_b =>
[(1+p, 0); (fs (1+i), 1)] ++ (* 2/1; 3/2, goto i+1 *)
[(0, 0); (0, 0); (0, 0); (0, 0)] (* filler *)
| mm2_dec_a j =>
[(4+p, 1)] ++ (* 3/2 *)
[(2+p, 0); (3+p, 0); (fs (1+i), 3)] ++ (* fail: 2/1; 2/1; 5/4 goto i+1 *)
[(5+p, 2); (fs j, 3)] (* success: 4/3; 5/4 goto j *)
| mm2_dec_b j => [(4+p, 2)] ++ (* 4/3 *)
[(2+p, 0); (3+p, 0); (fs (1+i), 3)] ++ (* fail: 2/1; 2/1; 5/4 goto i+1 *)
[(fs j, 3)] ++ (* success: 5/4 goto j *)
[(0, 0)] (* filler *)
end.
(* one counter machine encoding P in start cofiguration (1, (a0, b0)) *)
Definition M : list CM1.Instruction :=
encode_init ++ flat_map (fun '(a, i) => encode_instruction a i) (combine P (seq 1 (length P))).
(* κ a b c encodes mm2 counters (a, b) *)
Definition κ (a b c: nat) : nat := 2 ^ a * 3 ^ b * 5 ^ c.
(* encode mm2 config as cm1 config *)
Definition encodes_config (x: mm2_config) (y: CM1.Config) : Prop :=
match x with
| (i, (a, b)) => CM1.state y = fs i /\ exists n, CM1.value y = κ a b n
end.
Arguments nth_error : simpl never.
Arguments Nat.div : simpl never.
Arguments Nat.modulo : simpl never.
(* use: rewrite ?κ_norm. *)
Definition κ_norm := (@κ_pos, @κ_21, @κ_32, @κ_43, @κ_54, @κ_mod2, @κ_mod3, @κ_mod4).

Lemma init_M_b0 (n: nat) : n <= b0 ->
Nat.iter n (CM1.step M) {| CM1.state := a0+b0; CM1.value := κ (a0+b0) 0 0 |} =
{| CM1.state := a0+b0+n; CM1.value := κ (a0+(b0-n)) n 0 |}.