(* Arithmetic layer for the per-step invariant J (round 1 start; standalone, no TM). *)
Require Import Arith Lia List Bool.
Import ListNotations.
Definition tri : Type := (nat * nat * bool)%type.
Definition bv (d : bool) : nat := if d then 1 else 0.
(** binary value of the digits, first pair least significant *)
Fixpoint dv (P : list tri) : nat :=
match P with
| [] => 0
| (_,_,d) :: P' => bv d + 2 * dv P'
end.
Definition touch (x : tri) : tri := let '(p,q,d) := x in (S p, pred q, negb d).
Definition dig (x : tri) : bool := let '(_,_,d) := x in d.
Lemma dv_lt P : dv P < 2 ^ length P.
Proof.
induction P as [|[[p q] d] P IH]; cbn [dv length]; [cbn; lia|].
rewrite Nat.pow_succ_r'. destruct d; cbn [bv]; lia.
Qed.
(** a decrement: Z all 0 (become 1), borrow digit 1 -> 0 *)
Lemma dv_dec Z x x' R : Forall (fun y => dig y = false) Z -> dig x = true -> dig x' = false ->
dv (map touch Z ++ x' :: R) + 1 = dv (Z ++ x :: R).
Proof.
intros HZ Hx Hx'. induction Z as [|[[p q] d] Z IH]; cbn [map app dv touch].
- destruct x as [[p q] d], x' as [[p' q'] d']. cbn in Hx, Hx' |- *. subst. cbn. lia.
- inversion HZ as [|? ? Hd HZ']; subst. cbn in Hd. subst d. cbn [negb bv].
specialize (IH HZ'). lia.
Qed.
(** a merge at the borrow pair: the fused pair carries the next pair's digit *)
Lemma dv_merge Z x y y' R : Forall (fun y => dig y = false) Z -> dig x = true -> dig y' = dig y ->
dv (map touch Z ++ y' :: R) + 1 + 2 ^ length Z * dv (y :: R) = dv (Z ++ x :: y :: R).
Proof.
intros HZ Hx Hy. induction Z as [|[[p q] d] Z IH]; cbn [map app dv length touch].
- destruct x as [[p q] d], y as [[p1 q1] d1], y' as [[p2 q2] d2]. cbn in Hx, Hy |- *. subst. cbn. lia.
- inversion HZ as [|? ? Hd HZ']; subst. cbn in Hd. subst d. cbn [negb bv].
specialize (IH HZ'). rewrite Nat.pow_succ_r'. cbn [dv] in IH |- *. nia.
Qed.
Lemma dv_ones n : dv (repeat (0, 0, true) n) = 2 ^ n - 1.
Proof.
induction n as [|n IH]; cbn [repeat dv]; [reflexivity|].
rewrite Nat.pow_succ_r'. pose proof (Nat.pow_nonzero 2 n). cbn [bv]. lia.
Qed.
(** every suffix satisfies Pr *)
Fixpoint AllSuf (Pr : list tri -> Prop) (P : list tri) : Prop :=
match P with
| [] => True
| _ :: P' => Pr P /\ AllSuf Pr P'
end.
Lemma AllSuf_app Pr Z R : AllSuf Pr (Z ++ R) -> AllSuf Pr R.
Proof. induction Z as [|x Z IH]; cbn; [auto | intros [_ H]; auto]. Qed.