diff options
Diffstat (limited to 'src/LegacyArithmetic/Pow2BaseProofs.v')
-rw-r--r-- | src/LegacyArithmetic/Pow2BaseProofs.v | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/src/LegacyArithmetic/Pow2BaseProofs.v b/src/LegacyArithmetic/Pow2BaseProofs.v new file mode 100644 index 000000000..8a38275dd --- /dev/null +++ b/src/LegacyArithmetic/Pow2BaseProofs.v @@ -0,0 +1,555 @@ +Require Import Coq.ZArith.Zpower Coq.ZArith.ZArith Coq.micromega.Psatz. +Require Import Coq.Numbers.Natural.Peano.NPeano. +Require Import Coq.Lists.List. +Require Import Coq.funind.Recdef. +Require Import Crypto.Util.ListUtil Crypto.Util.ZUtil Crypto.Util.NatUtil. +Require Import Crypto.LegacyArithmetic.VerdiTactics. +Require Import Crypto.Util.Tactics.SpecializeBy. +Require Import Crypto.Util.Tactics.BreakMatch. +Require Import Crypto.Util.Tactics.UniquePose. +Require Import Crypto.Util.Tactics.RewriteHyp. +Require Import Crypto.LegacyArithmetic.Pow2Base. +Require Import Crypto.Util.Notations. +Require Export Crypto.Util.Bool. +Require Export Crypto.Util.FixCoqMistakes. +Local Open Scope Z_scope. + +Require Crypto.LegacyArithmetic.BaseSystemProofs. + +Create HintDb simpl_add_to_nth discriminated. +Create HintDb push_upper_bound discriminated. +Create HintDb pull_upper_bound discriminated. +Create HintDb push_base_from_limb_widths discriminated. +Create HintDb pull_base_from_limb_widths discriminated. + +Hint Extern 1 => progress autorewrite with push_upper_bound in * : push_upper_bound. +Hint Extern 1 => progress autorewrite with pull_upper_bound in * : pull_upper_bound. +Hint Extern 1 => progress autorewrite with push_base_from_limb_widths in * : push_base_from_limb_widths. +Hint Extern 1 => progress autorewrite with pull_base_from_limb_widths in * : pull_base_from_limb_widths. + +Section Pow2BaseProofs. + Context {limb_widths} (limb_widths_nonneg : forall w, In w limb_widths -> 0 <= w). + Local Notation base := (base_from_limb_widths limb_widths). + + Lemma base_from_limb_widths_length ls : length (base_from_limb_widths ls) = length ls. + Proof using Type. + clear limb_widths limb_widths_nonneg. + induction ls; [ reflexivity | simpl in * ]. + autorewrite with distr_length; auto. + Qed. + Hint Rewrite base_from_limb_widths_length : distr_length. + + Lemma base_from_limb_widths_cons : forall l0 l, + base_from_limb_widths (l0 :: l) = 1 :: map (Z.mul (two_p l0)) (base_from_limb_widths l). + Proof using Type. reflexivity. Qed. + Hint Rewrite base_from_limb_widths_cons : push_base_from_limb_widths. + Hint Rewrite <- base_from_limb_widths_cons : pull_base_from_limb_widths. + + Lemma base_from_limb_widths_nil : base_from_limb_widths nil = nil. + Proof using Type. reflexivity. Qed. + Hint Rewrite base_from_limb_widths_nil : push_base_from_limb_widths. + + Lemma firstn_base_from_limb_widths : forall n, firstn n (base_from_limb_widths limb_widths) = base_from_limb_widths (firstn n limb_widths). + Proof using Type. + clear limb_widths_nonneg. (* don't use this in the inductive hypothesis *) + induction limb_widths as [|l ls IHls]; intros [|n]; try reflexivity. + autorewrite with push_base_from_limb_widths push_firstn; boring. + Qed. + Hint Rewrite <- @firstn_base_from_limb_widths : push_base_from_limb_widths. + Hint Rewrite <- @firstn_base_from_limb_widths : pull_firstn. + Hint Rewrite @firstn_base_from_limb_widths : pull_base_from_limb_widths. + Hint Rewrite @firstn_base_from_limb_widths : push_firstn. + + Lemma sum_firstn_limb_widths_nonneg : forall n, 0 <= sum_firstn limb_widths n. + Proof using Type*. + unfold sum_firstn; intros. + apply fold_right_invariant; try omega. + eauto using Z.add_nonneg_nonneg, limb_widths_nonneg, In_firstn. + Qed. Hint Resolve sum_firstn_limb_widths_nonneg. + + Lemma base_from_limb_widths_step : forall i b w, (S i < length limb_widths)%nat -> + nth_error base i = Some b -> + nth_error limb_widths i = Some w -> + nth_error base (S i) = Some (two_p w * b). + Proof using Type. + clear limb_widths_nonneg. (* don't use this in the inductive hypothesis *) + induction limb_widths; intros ? ? ? ? nth_err_w nth_err_b; + unfold base_from_limb_widths in *; fold base_from_limb_widths in *; + [rewrite (@nil_length0 Z) in *; omega | ]. + simpl in *. + case_eq i; intros; subst. + + subst; apply nth_error_first in nth_err_w. + apply nth_error_first in nth_err_b; subst. + apply map_nth_error. + case_eq l; intros; subst; [simpl in *; omega | ]. + unfold base_from_limb_widths; fold base_from_limb_widths. + reflexivity. + + simpl in nth_err_w. + apply nth_error_map in nth_err_w. + destruct nth_err_w as [x [A B] ]. + subst. + replace (two_p w * (two_p a * x)) with (two_p a * (two_p w * x)) by ring. + apply map_nth_error. + apply IHl; auto. omega. + Qed. + + + Lemma nth_error_base : forall i, (i < length limb_widths)%nat -> + nth_error base i = Some (two_p (sum_firstn limb_widths i)). + Proof using Type*. + induction i; intros. + + unfold sum_firstn, base_from_limb_widths in *; case_eq limb_widths; try reflexivity. + intro lw_nil; rewrite lw_nil, (@nil_length0 Z) in *; omega. + + assert (i < length limb_widths)%nat as lt_i_length by omega. + specialize (IHi lt_i_length). + destruct (nth_error_length_exists_value _ _ lt_i_length) as [w nth_err_w]. + erewrite base_from_limb_widths_step; eauto. + f_equal. + simpl. + destruct (NPeano.Nat.eq_dec i 0). + - subst; unfold sum_firstn; simpl. + apply nth_error_exists_first in nth_err_w. + destruct nth_err_w as [l' lw_destruct]; subst. + simpl; ring_simplify. + f_equal; ring. + - erewrite sum_firstn_succ; eauto. + symmetry. + apply two_p_is_exp; auto using sum_firstn_limb_widths_nonneg. + apply limb_widths_nonneg. + eapply nth_error_value_In; eauto. + Qed. + + Lemma nth_default_base : forall d i, (i < length limb_widths)%nat -> + nth_default d base i = 2 ^ (sum_firstn limb_widths i). + Proof using Type*. + intros ? ? i_lt_length. + apply nth_error_value_eq_nth_default. + rewrite nth_error_base, two_p_correct by assumption. + reflexivity. + Qed. + + Lemma b0_1 : forall x : Z, limb_widths <> nil -> nth_default x base 0 = 1. + Proof using Type. + case_eq limb_widths; intros; [congruence | reflexivity]. + Qed. + + Lemma base_from_limb_widths_app : forall l0 l + (l0_nonneg : forall x, In x l0 -> 0 <= x) + (l_nonneg : forall x, In x l -> 0 <= x), + base_from_limb_widths (l0 ++ l) + = base_from_limb_widths l0 ++ map (Z.mul (two_p (sum_firstn l0 (length l0)))) (base_from_limb_widths l). + Proof using Type. + induction l0 as [|?? IHl0]. + { simpl; intros; rewrite <- map_id at 1; apply map_ext; intros; omega. } + { simpl; intros; rewrite !IHl0, !map_app, map_map, sum_firstn_succ_cons, two_p_is_exp by auto with znonzero. + do 2 f_equal; apply map_ext; intros; lia. } + Qed. + + Lemma skipn_base_from_limb_widths : forall n, skipn n (base_from_limb_widths limb_widths) = map (Z.mul (two_p (sum_firstn limb_widths n))) (base_from_limb_widths (skipn n limb_widths)). + Proof using Type*. + intro n; pose proof (base_from_limb_widths_app (firstn n limb_widths) (skipn n limb_widths)) as H. + specialize_by eauto using In_firstn, In_skipn. + autorewrite with simpl_firstn simpl_skipn in *. + rewrite H, skipn_app, skipn_all by auto with arith distr_length; clear H. + simpl; distr_length. + apply Min.min_case_strong; intro; + unfold sum_firstn; autorewrite with natsimplify simpl_skipn simpl_firstn; + reflexivity. + Qed. + Hint Rewrite <- @skipn_base_from_limb_widths : push_base_from_limb_widths. + Hint Rewrite <- @skipn_base_from_limb_widths : pull_skipn. + Hint Rewrite @skipn_base_from_limb_widths : pull_base_from_limb_widths. + Hint Rewrite @skipn_base_from_limb_widths : push_skipn. + + Lemma pow2_mod_bounded :forall lw us i, (forall w, In w lw -> 0 <= w) -> bounded lw us -> + Z.pow2_mod (nth_default 0 us i) (nth_default 0 lw i) = nth_default 0 us i. + Proof using Type. + clear. + repeat match goal with + | |- _ => progress (cbv [bounded]; intros) + | |- _ => break_if + | |- _ => apply Z.bits_inj' + | |- _ => rewrite Z.testbit_pow2_mod by (apply nth_default_preserves_properties; auto; omega) + | |- _ => reflexivity + end. + specialize (H0 i). + symmetry. + rewrite <- (Z.mod_pow2_bits_high (nth_default 0 us i) (nth_default 0 lw i) n); + [ rewrite Z.mod_small by omega; reflexivity | ]. + split; try omega. + apply nth_default_preserves_properties; auto; omega. + Qed. + + Lemma bounded_nil_iff : forall us, bounded nil us <-> (forall u, In u us -> u = 0). + Proof using Type. + clear. + split; cbv [bounded]; intros. + + edestruct (In_nth_error_value us u); try assumption. + specialize (H x). + replace u with (nth_default 0 us x) by (auto using nth_error_value_eq_nth_default). + rewrite nth_default_nil, Z.pow_0_r in H. + omega. + + rewrite nth_default_nil, Z.pow_0_r. + apply nth_default_preserves_properties; try omega. + intros. + apply H in H0. + omega. + Qed. + + Lemma bounded_iff : forall lw us, bounded lw us <-> forall i, 0 <= nth_default 0 us i < 2 ^ nth_default 0 lw i. + Proof using Type. + clear. + cbv [bounded]; intros. + reflexivity. + Qed. + + Lemma digit_select : forall us i, bounded limb_widths us -> + nth_default 0 us i = Z.pow2_mod (BaseSystem.decode base us >> sum_firstn limb_widths i) (nth_default 0 limb_widths i). + Proof using Type*. + intro; revert limb_widths limb_widths_nonneg; induction us; intros. + + rewrite nth_default_nil, BaseSystemProofs.decode_nil, Z.shiftr_0_l, Z.pow2_mod_spec, Z.mod_0_l by + (try (apply Z.pow_nonzero; try omega); apply nth_default_preserves_properties; auto; omega). + reflexivity. + + destruct i. + - rewrite nth_default_cons, sum_firstn_0, Z.shiftr_0_r. + destruct limb_widths as [|w lw]. + * cbv [base_from_limb_widths]. + rewrite <-pow2_mod_bounded with (lw := nil); rewrite bounded_nil_iff in *; auto using in_cons; + try solve [intros; exfalso; eauto using in_nil]. + rewrite !nth_default_nil, BaseSystemProofs.decode_base_nil; auto. + cbv. auto using in_eq. + * rewrite nth_default_cons, base_from_limb_widths_cons, BaseSystemProofs.peel_decode. + fold (BaseSystem.mul_each (two_p w)). + rewrite <-BaseSystemProofs.mul_each_base, BaseSystemProofs.mul_each_rep. + rewrite two_p_correct, (Z.mul_comm (2 ^ w)). + rewrite <-Z.shiftl_mul_pow2 by auto using in_eq. + rewrite bounded_iff in *. + specialize (H 0%nat); rewrite !nth_default_cons in H. + rewrite <-Z.lor_shiftl by (auto using in_eq; omega). + apply Z.bits_inj'; intros. + rewrite Z.testbit_pow2_mod by auto using in_eq. + break_if. { + autorewrite with Ztestbit; break_match; + try rewrite Z.testbit_neg_r with (n := n - w) by omega; + autorewrite with bool_congr; + f_equal; ring. + } { + replace a with (a mod 2 ^ w) by (auto using Z.mod_small). + apply Z.mod_pow2_bits_high. split; auto using in_eq; omega. + } + - rewrite nth_default_cons_S. + destruct limb_widths as [|w lw]. + * cbv [base_from_limb_widths]. + rewrite <-pow2_mod_bounded with (lw := nil); rewrite bounded_nil_iff in *; auto using in_cons. + rewrite sum_firstn_nil, !nth_default_nil, BaseSystemProofs.decode_base_nil, Z.shiftr_0_r. + apply nth_default_preserves_properties; intros; auto using in_cons. + f_equal; auto using in_cons. + * rewrite sum_firstn_succ_cons, nth_default_cons_S, base_from_limb_widths_cons, BaseSystemProofs.peel_decode. + fold (BaseSystem.mul_each (two_p w)). + rewrite <-BaseSystemProofs.mul_each_base, BaseSystemProofs.mul_each_rep. + rewrite two_p_correct, (Z.mul_comm (2 ^ w)). + rewrite <-Z.shiftl_mul_pow2 by auto using in_eq. + rewrite bounded_iff in *. + rewrite Z.shiftr_add_shiftl_high by first + [ pose proof (sum_firstn_nonnegative i lw); split; auto using in_eq; specialize_by auto using in_cons; omega + | specialize (H 0%nat); rewrite !nth_default_cons in H; omega ]. + rewrite IHus with (limb_widths := lw) by + (auto using in_cons; rewrite ?bounded_iff; intro j; specialize (H (S j)); + rewrite !nth_default_cons_S in H; assumption). + repeat f_equal; try ring. + Qed. + + Lemma nth_default_limb_widths_nonneg : forall i, 0 <= nth_default 0 limb_widths i. + Proof using Type*. + intros; apply nth_default_preserves_properties; auto; omega. + Qed. Hint Resolve nth_default_limb_widths_nonneg. + + Lemma decode_firstn_pow2_mod : forall us i, + (i <= length us)%nat -> + length us = length limb_widths -> + bounded limb_widths us -> + BaseSystem.decode' base (firstn i us) = Z.pow2_mod (BaseSystem.decode' base us) (sum_firstn limb_widths i). + Proof using Type*. + intros; induction i; + repeat match goal with + | |- _ => rewrite sum_firstn_0, BaseSystemProofs.decode_nil, Z.pow2_mod_0_r; reflexivity + | |- _ => progress distr_length + | |- _ => progress autorewrite with simpl_firstn + | |- _ => rewrite firstn_succ with (d := 0) + | |- _ => rewrite BaseSystemProofs.set_higher + | |- _ => rewrite nth_default_base + | |- _ => rewrite IHi + | |- _ => rewrite <-Z.lor_shiftl by (rewrite ?Z.pow2_mod_spec; try apply Z.mod_pos_bound; zero_bounds) + | |- appcontext[min ?x ?y] => (rewrite Nat.min_l by omega || rewrite Nat.min_r by omega) + | |- appcontext[2 ^ ?a * _] => rewrite (Z.mul_comm (2 ^ a)); rewrite <-Z.shiftl_mul_pow2 + | |- _ => solve [auto] + | |- _ => lia + end. + rewrite digit_select by assumption; apply Z.bits_inj'. + repeat match goal with + | |- _ => progress intros + | |- _ => progress autorewrite with Ztestbit + | |- _ => rewrite Z.testbit_pow2_mod by (omega || trivial) + | |- _ => break_if; try omega + | H : ?a < ?b |- appcontext[Z.testbit _ (?a - ?b)] => + rewrite (Z.testbit_neg_r _ (a-b)) by omega + | |- _ => reflexivity + | |- _ => solve [f_equal; ring] + | |- _ => rewrite sum_firstn_succ_default in *; + pose proof (nth_default_limb_widths_nonneg i); omega + end. + Qed. + + Lemma testbit_decode_firstn_high : forall us i n, + (i <= length us)%nat -> + length us = length limb_widths -> + bounded limb_widths us -> + sum_firstn limb_widths i <= n -> + Z.testbit (BaseSystem.decode base (firstn i us)) n = false. + Proof using Type*. + repeat match goal with + | |- _ => progress intros + | |- _ => progress autorewrite with Ztestbit + | |- _ => rewrite decode_firstn_pow2_mod + | |- _ => rewrite Z.testbit_pow2_mod + | |- _ => break_if + | |- _ => assumption + | |- _ => solve [auto] + | H : ?a <= ?b |- 0 <= ?b => assert (0 <= a) by (omega || auto); omega + end. + Qed. + + Lemma testbit_decode_high : forall us n, + length us = length limb_widths -> + bounded limb_widths us -> + sum_firstn limb_widths (length us) <= n -> + Z.testbit (BaseSystem.decode base us) n = false. + Proof using Type*. + intros. + erewrite <-(firstn_all _ us) by reflexivity. + auto using testbit_decode_firstn_high. + Qed. + + (** TODO: Figure out how to automate and clean up this proof *) + Lemma decode_nonneg : forall us, + length us = length limb_widths -> + bounded limb_widths us -> + 0 <= BaseSystem.decode base us. + Proof using Type*. + intros. + unfold bounded, BaseSystem.decode, BaseSystem.decode' in *; simpl in *. + pose 0 as zero. + assert (0 <= zero) by reflexivity. + replace base with (map (Z.mul (two_p zero)) base) + by (etransitivity; [ | apply map_id ]; apply map_ext; auto with zarith). + clearbody zero. + revert dependent zero. + generalize dependent limb_widths. + induction us as [|u us IHus]; intros [|w limb_widths'] ?? Hbounded ??; simpl in *; + try (reflexivity || congruence). + pose proof (Hbounded 0%nat) as Hbounded0. + pose proof (fun n => Hbounded (S n)) as HboundedS. + unfold nth_default, nth_error in Hbounded0. + unfold nth_default in HboundedS. + rewrite map_map. + unfold BaseSystem.accumulate at 1; simpl. + assert (0 < two_p zero) by (rewrite two_p_equiv; auto with zarith). + replace (map (fun x => two_p zero * (two_p w * x)) (base_from_limb_widths limb_widths')) with (map (Z.mul (two_p (zero + w))) (base_from_limb_widths limb_widths')) + by (apply map_ext; rewrite two_p_is_exp by auto with zarith omega; auto with zarith). + change 0 with (0 + 0) at 1. + apply Z.add_le_mono; simpl in *; auto with zarith. + Qed. + + Lemma decode_upper_bound : forall us, + length us = length limb_widths -> + bounded limb_widths us -> + 0 <= BaseSystem.decode base us < upper_bound limb_widths. + Proof using Type*. + cbv [upper_bound]; intros. + split. + { apply decode_nonneg; auto. } + { apply Z.testbit_false_bound; auto; intros. + rewrite testbit_decode_high; auto; + replace (length us) with (length limb_widths); try omega. } + Qed. + + Lemma decode_shift_app : forall us0 us1, (length (us0 ++ us1) <= length limb_widths)%nat -> + BaseSystem.decode base (us0 ++ us1) = (BaseSystem.decode (base_from_limb_widths (firstn (length us0) limb_widths)) us0) + ((BaseSystem.decode (base_from_limb_widths (skipn (length us0) limb_widths)) us1) << sum_firstn limb_widths (length us0)). + Proof using Type*. + unfold BaseSystem.decode; intros us0 us1 ?. + assert (0 <= sum_firstn limb_widths (length us0)) by auto using sum_firstn_nonnegative. + rewrite BaseSystemProofs.decode'_splice; autorewrite with push_firstn. + apply Z.add_cancel_l. + autorewrite with pull_base_from_limb_widths Zshift_to_pow zsimplify. + rewrite BaseSystemProofs.decode'_map_mul, two_p_correct; nia. + Qed. + + Lemma decode_shift : forall us u0, (length (u0 :: us) <= length limb_widths)%nat -> + BaseSystem.decode base (u0 :: us) = u0 + ((BaseSystem.decode (base_from_limb_widths (tl limb_widths)) us) << (nth_default 0 limb_widths 0)). + Proof using Type*. + intros; etransitivity; [ apply (decode_shift_app (u0::nil)); assumption | ]. + transitivity (u0 * 1 + 0 + ((BaseSystem.decode (base_from_limb_widths (tl limb_widths)) us) << (nth_default 0 limb_widths 0 + 0))); [ | autorewrite with zsimplify; reflexivity ]. + destruct limb_widths; distr_length; reflexivity. + Qed. + + Lemma upper_bound_nil : upper_bound nil = 1. + Proof using Type. reflexivity. Qed. + + Lemma upper_bound_cons x xs : 0 <= x -> 0 <= sum_firstn xs (length xs) -> upper_bound (x::xs) = 2^x * upper_bound xs. + Proof using Type. + intros Hx Hxs. + unfold upper_bound; simpl. + autorewrite with simpl_sum_firstn pull_Zpow. + reflexivity. + Qed. + + Lemma upper_bound_app xs ys : 0 <= sum_firstn xs (length xs) -> 0 <= sum_firstn ys (length ys) -> upper_bound (xs ++ ys) = upper_bound xs * upper_bound ys. + Proof using Type. + intros Hxs Hys. + unfold upper_bound; simpl. + autorewrite with distr_length simpl_sum_firstn pull_Zpow. + reflexivity. + Qed. + +End Pow2BaseProofs. +Hint Rewrite base_from_limb_widths_cons base_from_limb_widths_nil : push_base_from_limb_widths. +Hint Rewrite <- base_from_limb_widths_cons : pull_base_from_limb_widths. + +Hint Rewrite <- @firstn_base_from_limb_widths : push_base_from_limb_widths. +Hint Rewrite <- @firstn_base_from_limb_widths : pull_firstn. +Hint Rewrite @firstn_base_from_limb_widths : pull_base_from_limb_widths. +Hint Rewrite @firstn_base_from_limb_widths : push_firstn. +Hint Rewrite <- @skipn_base_from_limb_widths : push_base_from_limb_widths. +Hint Rewrite <- @skipn_base_from_limb_widths : pull_skipn. +Hint Rewrite @skipn_base_from_limb_widths : pull_base_from_limb_widths. +Hint Rewrite @skipn_base_from_limb_widths : push_skipn. + +Hint Rewrite @base_from_limb_widths_length : distr_length. +Hint Rewrite @upper_bound_nil @upper_bound_cons @upper_bound_app using solve [ eauto with znonzero ] : push_upper_bound. +Hint Rewrite <- @upper_bound_cons @upper_bound_app using solve [ eauto with znonzero ] : pull_upper_bound. + +Section UniformBase. + Context {width : Z} (limb_width_nonneg : 0 <= width). + Context (limb_widths : list Z) + (limb_widths_uniform : forall w, In w limb_widths -> w = width). + Local Notation base := (base_from_limb_widths limb_widths). + + Lemma bounded_uniform : forall us, (length us <= length limb_widths)%nat -> + (bounded limb_widths us <-> (forall u, In u us -> 0 <= u < 2 ^ width)). + Proof using Type*. + cbv [bounded]; split; intro A; intros. + + let G := fresh "G" in + match goal with H : In _ us |- _ => + eapply In_nth in H; destruct H as [? G]; destruct G as [? G]; + rewrite <-nth_default_eq in G; rewrite <-G end. + specialize (A x). + split; try eapply A. + eapply Z.lt_le_trans; try apply A. + apply nth_default_preserves_properties; [ | apply Z.pow_le_mono_r; omega ] . + intros; apply Z.eq_le_incl. + f_equal; auto. + + apply nth_default_preserves_properties_length_dep; + try solve [apply nth_default_preserves_properties; split; zero_bounds; rewrite limb_widths_uniform; auto || omega]. + intros; apply nth_default_preserves_properties_length_dep; try solve [intros; omega]. + let x := fresh "x" in intro x; intros; + replace x with width; try symmetry; auto. + Qed. + + Lemma uniform_limb_widths_nonneg : forall w, In w limb_widths -> 0 <= w. + Proof using Type*. + intros. + replace w with width by (symmetry; auto). + assumption. + Qed. + + Lemma nth_default_uniform_base_full : forall i, + nth_default 0 limb_widths i = if lt_dec i (length limb_widths) + then width else 0. + Admitted. + + Lemma nth_default_uniform_base : forall i, (i < length limb_widths)%nat -> + nth_default 0 limb_widths i = width. + Proof using Type*. + intros; rewrite nth_default_uniform_base_full. + edestruct lt_dec; omega. + Qed. + + Lemma sum_firstn_uniform_base : forall i, (i <= length limb_widths)%nat -> + sum_firstn limb_widths i = Z.of_nat i * width. + Proof using limb_widths_uniform. + clear limb_width_nonneg. (* clear this before induction so we don't depend on this *) + induction limb_widths as [|x xs IHxs]; (intros [|i] ?); + simpl @length in *; + autorewrite with simpl_sum_firstn push_Zof_nat zsimplify; + try reflexivity; + try omega. + assert (x = width) by auto with datatypes; subst. + rewrite IHxs by auto with datatypes omega; omega. + Qed. + + Lemma sum_firstn_uniform_base_strong : forall i, (length limb_widths <= i)%nat -> + sum_firstn limb_widths i = Z.of_nat (length limb_widths) * width. + Proof using limb_widths_uniform. + intros; rewrite sum_firstn_all, sum_firstn_uniform_base by omega; reflexivity. + Qed. + + Lemma upper_bound_uniform : upper_bound limb_widths = 2^(Z.of_nat (length limb_widths) * width). + Proof using limb_widths_uniform. + unfold upper_bound; rewrite sum_firstn_uniform_base_strong by omega; reflexivity. + Qed. + + (* TODO : move *) + Lemma decode_truncate_base : forall us bs, BaseSystem.decode bs us = BaseSystem.decode (firstn (length us) bs) us. + Proof using Type. + clear. + induction us; intros. + + rewrite !BaseSystemProofs.decode_nil; reflexivity. + + distr_length. + destruct bs. + - rewrite firstn_nil, !BaseSystemProofs.decode_base_nil; reflexivity. + - rewrite firstn_cons, !BaseSystemProofs.peel_decode. + f_equal. + apply IHus. + Qed. + + (* TODO : move *) + Lemma tl_repeat : forall {A} xs n (x : A), (forall y, In y xs -> y = x) -> + (n < length xs)%nat -> + firstn n xs = firstn n (tl xs). + Proof using Type. + intros. + erewrite (repeat_spec_eq xs) by first [ eassumption | reflexivity ]. + rewrite ListUtil.tl_repeat. + autorewrite with push_firstn. + apply f_equal; omega *. + Qed. + + Lemma decode_tl_base : forall us, (length us < length limb_widths)%nat -> + BaseSystem.decode base us = BaseSystem.decode (base_from_limb_widths (tl limb_widths)) us. + Proof using limb_widths_uniform. + intros. + match goal with |- BaseSystem.decode ?b1 _ = BaseSystem.decode ?b2 _ => + rewrite (decode_truncate_base _ b1), (decode_truncate_base _ b2) end. + rewrite !firstn_base_from_limb_widths. + do 2 f_equal. + eauto using tl_repeat. + Qed. + + Lemma decode_shift_uniform_tl : forall us u0, (length (u0 :: us) <= length limb_widths)%nat -> + BaseSystem.decode base (u0 :: us) = u0 + ((BaseSystem.decode (base_from_limb_widths (tl limb_widths)) us) << width). + Proof using Type*. + intros. + rewrite <- (nth_default_uniform_base 0) by distr_length. + rewrite decode_shift by auto using uniform_limb_widths_nonneg. + reflexivity. + Qed. + + Lemma decode_shift_uniform_app : forall us0 us1, (length (us0 ++ us1) <= length limb_widths)%nat -> + BaseSystem.decode base (us0 ++ us1) = (BaseSystem.decode (base_from_limb_widths (firstn (length us0) limb_widths)) us0) + ((BaseSystem.decode (base_from_limb_widths (skipn (length us0) limb_widths)) us1) << (Z.of_nat (length us0) * width)). + Proof using Type*. + intros. + rewrite <- sum_firstn_uniform_base by (distr_length; omega). + rewrite decode_shift_app by auto using uniform_limb_widths_nonneg. + reflexivity. + Qed. +End UniformBase.
\ No newline at end of file |