Section MM2_CM2.
Variable (P: list mm2_instr). (* MM2 program *)
Variables (a0 b0: nat). (* MM2 initial counters *)
Definition mm2_config : Set := (nat*(nat*nat)).
(* instruction index map *)
Definition fs (i: nat) : CM2.State :=
if i is S i then i + a0 + b0 else (length P) + a0 + b0.
(* encode instruction mmi at position i using index map fs for current cm2 state p *)
Definition encode_instruction (mmi: mm2_instr) : CM2.Instruction :=
match mmi with
| mm2_inc_a => CM2.inc false
| mm2_inc_b => CM2.inc true
| mm2_dec_a j => CM2.dec false (fs j)
| mm2_dec_b j => CM2.dec true (fs j)
end.
(* two counter machine encoding P in start cofiguration (0, (0, 0)) *)
Definition M : list CM2.Instruction :=
(repeat (CM2.inc false) a0) ++ (repeat (CM2.inc true) b0) ++ map encode_instruction P.
(* encode mm2 config as cm2 config *)
Definition encode_config (x: mm2_config) : CM2.Config :=
let: (i, (a, b)) := x in {| CM2.state := fs i; CM2.value1 := a; CM2.value2 := b |}.
(* relation between M indices and P indices *)
Inductive program_index : nat -> Prop :=
| seek_M_None {i} : nth_error M (fs i) = None -> (forall op, not (mm2_instr_at op i P)) -> program_index i
| seek_M_Some {i op} : nth_error M (fs (1+i)) = Some (encode_instruction op) ->
mm2_instr_at op (1+i) P -> program_index (1+i).

(* P simulates M *)
Lemma M_to_P (n: nat) (x: mm2_config) :
exists y, Nat.iter n (CM2.step M) (encode_config x) = encode_config y /\ clos_refl_trans _ (mm2_step P) x y.