Local Notation "l /F/ x -[ k ]-> y" := (fractran_steps l k x y) (at level 70, no associativity).(* Fractran simulates MM *)

(*       let a MM program 1: INC ... k: DEC ... n: _ *)
(*       with variables x1...xm *)

(*    we use p1...pn,q1...qm distinct primes and  *)
(*    encode the state (i,v1,...,vm) *)
(*    as p1^0*...*pi^1*...*pn^0*q1^v1*...*qm^vm *)

(*    i: INC xu   ---> (qu*p(i+1) / pi) *)
(*    i: DEC xu j ---> (p(i+1) / pi*qu) and (pj / pi) (the second constraint should appear AFTER in the list) *)

Definition encode_state {n} (c : nat * vec nat n) := ps (fst c) * @exp n 0 (snd c).Definition encode_inc n  i (u : pos n) := (ps (i + 1) * qs u, ps i).Definition encode_dec n  i (u : pos n) (_ : nat) := (ps (i + 1), ps i * qs u).Definition encode_dec2 n i (u : pos n) j := (ps j, ps i).Definition encode_one_instr m i (rho : mm_instr m) :=
  match rho with
    | INC u   => encode_inc i u :: nil
    | DEC u j => encode_dec i u j :: encode_dec2 i u j :: nil
  end.Fixpoint encode_mm_instr m i (l : list (mm_instr m)) : list (nat * nat) :=
  match l with
    | nil          => nil
    | rho :: l => encode_one_instr i rho ++ encode_mm_instr (S i) l
  end.Fact encode_mm_instr_app m i l r : @encode_mm_instr m i (l++r) = encode_mm_instr i l++encode_mm_instr (length l+i) r.Fact encode_mm_instr_regular n i l : Forall (fun c => fst c <> 0 /\ snd c <> 0) (@encode_mm_instr n i l).Fact encode_mm_instr_regular' n i l : fractran_regular (@encode_mm_instr n i l).Fact encode_mm_instr_in_inv n i P el c er : 
          @encode_mm_instr n i P = el++c::er
       -> exists l rho r, P = l++rho::r /\ In c (encode_one_instr (length l+i) rho).Local Notation divides_mult_inv := prime_div_mult.Local Ltac inv H := inversion H; subst; clear H.

(* Specifications: *)
Lemma divides_encode_state i k n v : divides (ps i) (@encode_state n (k,v)) -> i = k.
Lemma qs_exp i n u (v : vec nat n) : divides (qs u) (encode_state (i,v)) <-> divides (qs u) (exp 0 v).