diff options
Diffstat (limited to 'src/Arithmetic/Saturated/MontgomeryAPI.v')
-rw-r--r-- | src/Arithmetic/Saturated/MontgomeryAPI.v | 691 |
1 files changed, 0 insertions, 691 deletions
diff --git a/src/Arithmetic/Saturated/MontgomeryAPI.v b/src/Arithmetic/Saturated/MontgomeryAPI.v deleted file mode 100644 index d08fe7a8b..000000000 --- a/src/Arithmetic/Saturated/MontgomeryAPI.v +++ /dev/null @@ -1,691 +0,0 @@ -Require Import Coq.ZArith.ZArith. -Require Import Coq.micromega.Lia. -Require Import Coq.Lists.List. -Local Open Scope Z_scope. - -Require Import Crypto.Arithmetic.Core. -Require Import Crypto.Arithmetic.Saturated.Core. -Require Import Crypto.Arithmetic.Saturated.UniformWeight. -Require Import Crypto.Arithmetic.Saturated.Wrappers. -Require Import Crypto.Arithmetic.Saturated.AddSub. -Require Import Crypto.Util.LetIn Crypto.Util.CPSUtil. -Require Import Crypto.Util.Tuple Crypto.Util.LetIn. -Require Import Crypto.Util.Decidable. -Require Import Crypto.Util.ListUtil. -Require Import Crypto.Util.ZUtil.Tactics.ZeroBounds. -Require Import Crypto.Util.ZUtil.Tactics.DivModToQuotRem. -Require Import Crypto.Util.ZUtil.Modulo. -Require Import Crypto.Util.ZUtil.Definitions. -Require Import Crypto.Util.ZUtil.CPS. -Require Import Crypto.Util.ZUtil.Zselect. -Require Import Crypto.Util.ZUtil.AddGetCarry. -Require Import Crypto.Util.ZUtil.MulSplit. -Require Import Crypto.Util.ZUtil.Div. -Require Import Crypto.Util.ZUtil.Tactics.LtbToLt. -Require Import Crypto.Util.ZUtil.Opp. -Require Import Crypto.Util.Tactics.UniquePose. -Local Notation "A ^ n" := (tuple A n) : type_scope. - -Section API. - Context (bound : Z) {bound_pos : bound > 0}. - Definition T : nat -> Type := tuple Z. - - (* lowest limb is less than its bound; this is required for [divmod] - to simply separate the lowest limb from the rest and be equivalent - to normal div/mod with [bound]. *) - Local Notation small := (@small bound). - - Definition zero {n:nat} : T n := B.Positional.zeros n. - - (** Returns 0 iff all limbs are 0 *) - Definition nonzero_cps {n} (p : T n) {cpsT} (f : Z -> cpsT) : cpsT - := CPSUtil.to_list_cps _ p (fun p => CPSUtil.fold_right_cps runtime_lor 0%Z p f). - Definition nonzero {n} (p : T n) : Z - := nonzero_cps p id. - - Definition join0_cps {n:nat} (p : T n) {R} (f:T (S n) -> R) - := Tuple.left_append_cps 0 p f. - Definition join0 {n} p : T (S n) := @join0_cps n p _ id. - - Definition divmod_cps {n} (p : T (S n)) {R} (f:T n * Z->R) : R - := Tuple.tl_cps p (fun d => Tuple.hd_cps p (fun m => f (d, m))). - Definition divmod {n} p : T n * Z := @divmod_cps n p _ id. - - Definition drop_high_cps {n : nat} (p : T (S n)) {R} (f:T n->R) - := Tuple.left_tl_cps p f. - Definition drop_high {n} p : T n := @drop_high_cps n p _ id. - - Definition scmul_cps {n} (c : Z) (p : T n) {R} (f:T (S n)->R) := - Columns.mul_cps (n1:=1) (n3:=S n) (uweight bound) bound c p - (* The carry that comes out of Columns.mul_cps will be 0, since - (S n) limbs is enough to hold the result of the - multiplication, so we can safely discard it. *) - (fun carry_result =>f (snd carry_result)). - Definition scmul {n} c p : T (S n) := @scmul_cps n c p _ id. - - Definition add_cps {n} (p q: T n) {R} (f:T (S n)->R) := - B.Positional.sat_add_cps (s:=bound) p q _ - (* join the last carry *) - (fun carry_result => Tuple.left_append_cps (fst carry_result) (snd carry_result) f). - Definition add {n} p q : T (S n) := @add_cps n p q _ id. - - (* Wrappers for additions with slightly uneven limb counts *) - Definition add_S1_cps {n} (p: T (S n)) (q: T n) {R} (f:T (S (S n))->R) := - join0_cps q (fun Q => add_cps p Q f). - Definition add_S1 {n} p q := @add_S1_cps n p q _ id. - Definition add_S2_cps {n} (p: T n) (q: T (S n)) {R} (f:T (S (S n))->R) := - join0_cps p (fun P => add_cps P q f). - Definition add_S2 {n} p q := @add_S2_cps n p q _ id. - - Definition sub_then_maybe_add_cps {n} mask (p q r : T n) - {R} (f:T n -> R) := - B.Positional.sat_sub_cps (s:=bound) p q _ - (* the carry will be 0 unless we underflow--we do the addition only - in the underflow case *) - (fun carry_result => - B.Positional.select_cps mask (fst carry_result) r - (fun selected => join0_cps selected - (fun selected' => - B.Positional.sat_add_cps (s:=bound) (left_append (- (fst carry_result))%RT (snd carry_result)) selected' _ - (* We can now safely discard the carry and the highest digit. - This relies on the precondition that p - q + r < bound^n. *) - (fun carry_result' => drop_high_cps (snd carry_result') f)))). - Definition sub_then_maybe_add {n} mask (p q r : T n) := - sub_then_maybe_add_cps mask p q r id. - - (* Subtract q if and only if p >= q. We rely on the preconditions - that 0 <= p < 2*q and q < bound^n (this ensures the output is less - than bound^n). *) - Definition conditional_sub_cps {n} (p:Z^S n) (q:Z^n) R (f:Z^n->R) := - join0_cps q - (fun qq => B.Positional.sat_sub_cps (s:=bound) p qq _ - (* if carry is zero, we select the result of the subtraction, - otherwise the first input *) - (fun carry_result => - Tuple.map2_cps (Z.zselect (fst carry_result)) (snd carry_result) p - (* in either case, since our result must be < q and therefore < - bound^n, we can drop the high digit *) - (fun r => drop_high_cps r f))). - Definition conditional_sub {n} p q := @conditional_sub_cps n p q _ id. - - Hint Opaque join0 divmod drop_high scmul add sub_then_maybe_add conditional_sub : uncps. - - Section CPSProofs. - - Local Ltac prove_id := - repeat autounfold; - repeat (intros; autorewrite with uncps push_id); - reflexivity. - - Lemma nonzero_id n p {cpsT} f : @nonzero_cps n p cpsT f = f (@nonzero n p). - Proof. cbv [nonzero nonzero_cps]. prove_id. Qed. - - Lemma join0_id n p R f : - @join0_cps n p R f = f (join0 p). - Proof. cbv [join0_cps join0]. prove_id. Qed. - - Lemma divmod_id n p R f : - @divmod_cps n p R f = f (divmod p). - Proof. cbv [divmod_cps divmod]; prove_id. Qed. - - Lemma drop_high_id n p R f : - @drop_high_cps n p R f = f (drop_high p). - Proof. cbv [drop_high_cps drop_high]; prove_id. Qed. - Hint Rewrite drop_high_id : uncps. - - Lemma scmul_id n c p R f : - @scmul_cps n c p R f = f (scmul c p). - Proof. cbv [scmul_cps scmul]. prove_id. Qed. - - Lemma add_id n p q R f : - @add_cps n p q R f = f (add p q). - Proof. cbv [add_cps add Let_In]. prove_id. Qed. - Hint Rewrite add_id : uncps. - - Lemma add_S1_id n p q R f : - @add_S1_cps n p q R f = f (add_S1 p q). - Proof. cbv [add_S1_cps add_S1 join0_cps]. prove_id. Qed. - - Lemma add_S2_id n p q R f : - @add_S2_cps n p q R f = f (add_S2 p q). - Proof. cbv [add_S2_cps add_S2 join0_cps]. prove_id. Qed. - - Lemma sub_then_maybe_add_id n mask p q r R f : - @sub_then_maybe_add_cps n mask p q r R f = f (sub_then_maybe_add mask p q r). - Proof. cbv [sub_then_maybe_add_cps sub_then_maybe_add join0_cps Let_In]. prove_id. Qed. - - Lemma conditional_sub_id n p q R f : - @conditional_sub_cps n p q R f = f (conditional_sub p q). - Proof. cbv [conditional_sub_cps conditional_sub join0_cps Let_In]. prove_id. Qed. - - End CPSProofs. - Hint Rewrite nonzero_id join0_id divmod_id drop_high_id scmul_id add_id sub_then_maybe_add_id conditional_sub_id : uncps. - - Section Proofs. - - Definition eval {n} (p : T n) : Z := - B.Positional.eval (uweight bound) p. - - Definition encode n (z : Z) : T n := - B.Positional.encode (uweight bound) (modulo_cps:=@modulo_cps) (div_cps:=@div_cps) z. - - Lemma eval_small n (p : T n) (Hsmall : small p) : - 0 <= eval p < uweight bound n. - Proof. - cbv [small eval] in *; intros. - induction n; cbv [T uweight] in *; [destruct p|rewrite (subst_left_append p)]; - repeat match goal with - | _ => progress autorewrite with push_basesystem_eval - | _ => rewrite Z.pow_0_r - | _ => specialize (IHn (left_tl p)) - | _ => - let H := fresh "H" in - match type of IHn with - ?P -> _ => assert P as H by auto using Tuple.In_to_list_left_tl; - specialize (IHn H) - end - | |- context [?b ^ Z.of_nat (S ?n)] => - replace (b ^ Z.of_nat (S n)) with (b ^ Z.of_nat n * b) by - (rewrite Nat2Z.inj_succ, <-Z.add_1_r, Z.pow_add_r, - Z.pow_1_r by (omega || auto using Nat2Z.is_nonneg); - reflexivity) - | _ => omega - end. - - specialize (Hsmall _ (Tuple.In_left_hd _ p)). - split; [Z.zero_bounds; omega |]. - apply Z.lt_le_trans with (m:=bound^Z.of_nat n * (left_hd p+1)). - { rewrite Z.mul_add_distr_l. - apply Z.add_le_lt_mono; omega. } - { apply Z.mul_le_mono_nonneg; omega. } - Qed. - - Lemma small_encode n (v : Z) (Hsmall : 0 <= v < uweight bound n) - : small (encode n v). - Proof. - Admitted. (* TODO(jadep): prove me *) - - Lemma eval_encode n (v : Z) (Hsmall : 0 <= v < uweight bound n) - : eval (encode n v) = v. - Proof. - destruct n as [|n]. - { cbv -[Z.le Z.lt Z.gt] in *; omega. } - { cbv [eval encode]. - pose proof (@uweight_divides _ bound_pos) as Hdiv. - apply B.Positional.eval_encode; try reflexivity; - eauto using modulo_id, div_id, div_mod, uweight_nonzero. - { intros i ?; specialize (Hdiv i); omega. } } - Qed. - - Lemma eval_zero n : eval (@zero n) = 0. - Proof. - cbv [eval zero]. - autorewrite with push_basesystem_eval. - reflexivity. - Qed. - - Lemma small_zero n : small (@zero n). - Proof. - cbv [zero small B.Positional.zeros]. destruct n; [simpl;tauto|]. - rewrite to_list_repeat. - intros x H; apply repeat_spec in H; subst x; omega. - Qed. - - Lemma small_hd n p : @small (S n) p -> 0 <= hd p < bound. - Proof. - cbv [small]. let H := fresh "H" in intro H; apply H. - rewrite (subst_append p). rewrite to_list_append, hd_append. - apply in_eq. - Qed. - - Lemma In_to_list_tl {A n} (p : A^(S n)) x : - In x (to_list n (tl p)) -> In x (to_list (S n) p). - Proof. - intros. rewrite (subst_append p). - rewrite to_list_append. simpl In. tauto. - Qed. - - Lemma small_tl n p : @small (S n) p -> small (tl p). - Proof. - cbv [small]. let H := fresh "H" in intros H ? ?; apply H. - auto using In_to_list_tl. - Qed. - - Lemma add_nonneg_zero_iff a b c : 0 <= a -> 0 <= b -> 0 < c -> - a = 0 /\ b = 0 <-> a + c * b = 0. - Proof. nia. Qed. - - Lemma eval_pair n (p : T (S (S n))) : small p -> - (snd p = 0 /\ eval (n:=S n) (fst p) = 0) <-> eval p = 0. - Proof. - intro Hsmall. cbv [eval]. - rewrite uweight_eval_step with (p:=p). - change (fst p) with (tl p). change (snd p) with (hd p). - apply add_nonneg_zero_iff; try omega. - { apply small_hd in Hsmall. omega. } - { apply small_tl, eval_small in Hsmall. - cbv [eval] in Hsmall; omega. } - Qed. - - Lemma eval_nonzero n p : small p -> @nonzero n p = 0 <-> eval p = 0. - Proof. - destruct n as [|n]. - { compute; split; trivial. } - induction n as [|n IHn]. - { simpl; rewrite Z.lor_0_r; unfold eval, id. - cbv -[Z.add iff]. - rewrite Z.add_0_r. - destruct p; omega. } - { destruct p as [ps p]; specialize (IHn ps). - unfold nonzero, nonzero_cps in *. - autorewrite with uncps in *. - unfold id in *. - setoid_rewrite to_list_S. - set (k := S n) in *; simpl in *. - intro Hsmall. - rewrite Z.lor_eq_0_iff, IHn - by (hnf in Hsmall |- *; simpl in *; eauto); - clear IHn. - exact (eval_pair n (ps, p) Hsmall). } - Qed. - - Lemma eval_join0 n p - : eval (@join0 n p) = eval p. - Proof. - cbv [join0 join0_cps eval]. autorewrite with uncps push_id. - rewrite B.Positional.eval_left_append. ring. - Qed. - - Local Ltac pose_uweight bound := - match goal with H : bound > 0 |- _ => - pose proof (uweight_0 bound); - pose proof (@uweight_positive bound H); - pose proof (@uweight_nonzero bound H); - pose proof (@uweight_multiples bound); - pose proof (@uweight_divides bound H) - end. - - Local Ltac pose_all := - pose_uweight bound; - pose proof Z.add_get_carry_full_div; - pose proof Z.add_get_carry_full_mod; - pose proof Z.mul_split_div; pose proof Z.mul_split_mod; - pose proof div_correct; pose proof modulo_correct; - pose proof @div_id; pose proof @modulo_id; - pose proof @Z.add_get_carry_full_cps_correct; - pose proof @Z.mul_split_cps_correct; - pose proof @Z.mul_split_cps'_correct. - - Lemma eval_add n p q : - eval (@add n p q) = eval p + eval q. - Proof. - intros. pose_all. cbv [add_cps add eval Let_In]. - autorewrite with uncps push_id cancel_pair push_basesystem_eval. - symmetry; auto using Z.div_mod. - Qed. - - Lemma eval_add_same n p q - : eval (@add n p q) = eval p + eval q. - Proof. apply eval_add; omega. Qed. - Lemma eval_add_S1 n p q - : eval (@add_S1 n p q) = eval p + eval q. - Proof. - cbv [add_S1 add_S1_cps]. autorewrite with uncps push_id. - rewrite eval_add; rewrite eval_join0; reflexivity. - Qed. - Lemma eval_add_S2 n p q - : eval (@add_S2 n p q) = eval p + eval q. - Proof. - cbv [add_S2 add_S2_cps]. autorewrite with uncps push_id. - rewrite eval_add; rewrite eval_join0; reflexivity. - Qed. - Hint Rewrite eval_add_same eval_add_S1 eval_add_S2 using (omega || assumption): push_basesystem_eval. - - Local Definition compact {n} := Columns.compact (n:=n) (add_get_carry_cps:=@Z.add_get_carry_full_cps) (div_cps:=@div_cps) (modulo_cps:=@modulo_cps) (uweight bound). - Local Definition compact_digit := Columns.compact_digit (add_get_carry_cps:=@Z.add_get_carry_full_cps) (div_cps:=@div_cps) (modulo_cps:=@modulo_cps) (uweight bound). - Lemma small_compact {n} (p:(list Z)^n) : small (snd (compact p)). - Proof. - pose_all. - match goal with - |- ?G => assert (G /\ fst (compact p) = fst (compact p)); [|tauto] - end. (* assert a dummy second statement so that fst (compact x) is in context *) - cbv [compact Columns.compact Columns.compact_cps small - Columns.compact_step Columns.compact_step_cps]; - autorewrite with uncps push_id. - change (fun i s a => Columns.compact_digit_cps (uweight bound) i (s :: a) id) - with (fun i s a => compact_digit i (s :: a)). - remember (fun i s a => compact_digit i (s :: a)) as f. - - apply @mapi_with'_linvariant with (n:=n) (f:=f) (inp:=p); - intros; [|simpl; tauto]. split; [|reflexivity]. - let P := fresh "H" in - match goal with H : _ /\ _ |- _ => destruct H end. - destruct n0; subst f. - { cbv [compact_digit uweight to_list to_list' In]. - rewrite Columns.compact_digit_mod - by (assumption || (intros; autorewrite with uncps push_id; auto)). - rewrite Z.pow_0_r, Z.pow_1_r, Z.div_1_r. intros x ?. - match goal with - H : _ \/ False |- _ => destruct H; [|exfalso; assumption] end. - subst x. apply Z.mod_pos_bound, Z.gt_lt, bound_pos. } - { rewrite Tuple.to_list_left_append. - let H := fresh "H" in - intros x H; apply in_app_or in H; destruct H; - [solve[auto]| cbv [In] in H; destruct H; - [|exfalso; assumption] ]. - subst x. cbv [compact_digit]. - rewrite Columns.compact_digit_mod - by (assumption || (intros; autorewrite with uncps push_id; auto)). - rewrite !uweight_succ, Z.div_mul by - (apply Z.neq_mul_0; split; auto; omega). - apply Z.mod_pos_bound, Z.gt_lt, bound_pos. } - Qed. - - Lemma small_left_append {n} b x : - 0 <= x < bound -> small b -> small (@left_append _ n x b). - Proof. - intros. - cbv [small]. - setoid_rewrite Tuple.to_list_left_append. - setoid_rewrite in_app_iff. - intros y HIn; destruct HIn as [HIn|[]]; (contradiction||omega||eauto). - Qed. - - Lemma small_add n a b : - (2 <= bound) -> - small a -> small b -> small (@add n a b). - Proof. - intros. - cbv [add add_cps]; autorewrite with uncps push_id in *. - pose proof @B.Positional.small_sat_add bound ltac:(omega) _ a b. - eapply small_left_append; eauto. - rewrite @B.Positional.sat_add_div by omega. - repeat match goal with H:_|-_=> unique pose proof (eval_small _ _ H) end. - cbv [eval] in *; Z.div_mod_to_quot_rem_in_goal; nia. - Qed. - - Lemma small_join0 {n} b : small b -> small (@join0 n b). - Proof. - cbv [join0 join0_cps]; autorewrite with uncps push_id in *. - eapply small_left_append; omega. - Qed. - - Lemma small_add_S1 n a b : - (2 <= bound) -> - small a -> small b -> small (@add_S1 n a b). - Proof. - intros. - cbv [add_S1 add_S1_cps Let_In]; autorewrite with uncps push_id in *. - eauto using small_add, small_join0. - Qed. - - Lemma small_left_tl n (v:T (S n)) : small v -> small (left_tl v). - Proof. cbv [small]. auto using Tuple.In_to_list_left_tl. Qed. - - Lemma eval_drop_high n v : - small v -> eval (@drop_high n v) = eval v mod (uweight bound n). - Proof. - cbv [drop_high drop_high_cps eval]. - rewrite Tuple.left_tl_cps_correct, push_id. (* TODO : for some reason autorewrite with uncps doesn't work here *) - intro H. apply small_left_tl in H. - rewrite (subst_left_append v) at 2. - autorewrite with push_basesystem_eval. - apply eval_small in H. - rewrite Z.mod_add_l' by (pose_uweight bound; auto). - rewrite Z.mod_small; auto. - Qed. - - Lemma small_drop_high n v : small v -> small (@drop_high n v). - Proof. - cbv [drop_high drop_high_cps]. - rewrite Tuple.left_tl_cps_correct, push_id. - apply small_left_tl. - Qed. - - Lemma div_nonzero_neg_iff x y : x < y -> 0 < y -> - - (x / y) = 0 <-> x <? 0 = false. - Proof. - repeat match goal with - | _ => progress intros - | _ => rewrite Z.ltb_ge - | _ => rewrite Z.opp_eq_0_iff - | _ => rewrite Z.div_small_iff by omega - | _ => split - | _ => omega - end. - Qed. - - Lemma eval_sub_then_maybe_add n mask p q r: - small p -> small q -> small r -> - (map (Z.land mask) r = r) -> - (0 <= eval p < eval r) -> (0 <= eval q < eval r) -> - eval (@sub_then_maybe_add n mask p q r) = eval p - eval q + (if eval p - eval q <? 0 then eval r else 0). - Proof. - pose_all. - pose proof (@uweight_le_mono _ bound_pos n (S n) (Nat.le_succ_diag_r _)). - intros. - repeat match goal with - | _ => progress (intros; cbv [eval runtime_opp sub_then_maybe_add sub_then_maybe_add_cps] in * ) - | _ => progress autorewrite with uncps push_id push_basesystem_eval - | _ => rewrite eval_drop_high by (apply @B.Positional.small_sat_add; omega) - | _ => rewrite B.Positional.sat_sub_mod by omega - | _ => rewrite B.Positional.sat_sub_div by omega - | _ => rewrite B.Positional.sat_add_mod by omega - | _ => rewrite B.Positional.eval_left_append - | _ => rewrite eval_join0 - | H : small _ |- _ => apply eval_small in H - end. - let H := fresh "H" in - match goal with |- context [- (?X / ?Y) = 0] => - assert ((- (X / Y) = 0) <-> X <? 0 = false) as H - by (apply div_nonzero_neg_iff; omega) - end; destruct H. - break_match; try match goal with - H : ?x = ?x -> _ |- _ - => specialize (H (eq_refl x)) end; - try congruence; - match goal with - | H : _ |- _ => rewrite Z.ltb_ge in H - | H : _ |- _ => rewrite Z.ltb_lt in H - end. - { repeat (rewrite Z.mod_small; try omega). } - { rewrite !Z.mul_opp_r, Z.opp_involutive. - rewrite Z.mul_div_eq_full by (subst; auto). - match goal with |- context [?a - ?b + ?b] => - replace (a - b + b) with a by ring end. - repeat (rewrite Z.mod_small; try omega). } - Qed. - - Lemma small_sub_then_maybe_add n mask (p q r : T n) : - small (sub_then_maybe_add mask p q r). - Proof. - cbv [sub_then_maybe_add_cps sub_then_maybe_add]; intros. - repeat progress autounfold. autorewrite with uncps push_id. - apply small_drop_high, @B.Positional.small_sat_add; omega. - Qed. - - Lemma map2_zselect n cond x y : - Tuple.map2 (n:=n) (Z.zselect cond) x y = if dec (cond = 0) then x else y. - Proof. - unfold Z.zselect. - break_innermost_match; Z.ltb_to_lt; subst; try omega; - [ rewrite Tuple.map2_fst, Tuple.map_id - | rewrite Tuple.map2_snd, Tuple.map_id ]; - reflexivity. - Qed. - - Lemma eval_conditional_sub_nz n (p:T (S n)) (q:T n) - (n_nonzero: (n <> 0)%nat) (psmall : small p) (qsmall : small q): - 0 <= eval p < eval q + uweight bound n -> - eval (conditional_sub p q) = eval p + (if eval q <=? eval p then - eval q else 0). - Proof. - pose_all. - pose proof (@uweight_le_mono _ bound_pos n (S n) (Nat.le_succ_diag_r _)). - intros. - repeat match goal with - | _ => progress (intros; cbv [eval conditional_sub conditional_sub_cps] in * ) - | _ => progress autorewrite with uncps push_id push_basesystem_eval - | _ => rewrite eval_drop_high - by (break_match; try assumption; apply @B.Positional.small_sat_sub; omega) - | _ => rewrite map2_zselect - | _ => rewrite B.Positional.sat_sub_mod by omega - | _ => rewrite B.Positional.sat_sub_div by omega - | _ => rewrite B.Positional.sat_add_mod by omega - | _ => rewrite B.Positional.eval_left_append - | _ => rewrite eval_join0 - | H : small _ |- _ => apply eval_small in H - end. - let H := fresh "H" in - match goal with |- context [- (?X / ?Y) = 0] => - assert ((- (X / Y) = 0) <-> X <? 0 = false) as H - by (apply div_nonzero_neg_iff; omega) - end; destruct H. - break_match; try match goal with - H : ?x = ?x -> _ |- _ - => specialize (H (eq_refl x)) end; - repeat match goal with - | H : _ |- _ => rewrite Z.leb_gt in H - | H : _ |- _ => rewrite Z.leb_le in H - | H : _ |- _ => rewrite Z.ltb_lt in H - | H : _ |- _ => rewrite Z.ltb_ge in H - end; try omega. - { rewrite @B.Positional.sat_sub_mod by omega. - rewrite eval_join0; cbv [eval]. - repeat (rewrite Z.mod_small; try omega). } - { repeat (rewrite Z.mod_small; try omega). } - Qed. - - Lemma eval_conditional_sub n (p:T (S n)) (q:T n) - (psmall : small p) (qsmall : small q) : - 0 <= eval p < eval q + uweight bound n -> - eval (conditional_sub p q) = eval p + (if eval q <=? eval p then - eval q else 0). - Proof. - destruct n; [|solve[auto using eval_conditional_sub_nz]]. - repeat match goal with - | _ => progress (intros; cbv [T tuple tuple'] in p, q) - | q : unit |- _ => destruct q - | _ => progress (cbv [conditional_sub conditional_sub_cps eval] in * ) - | _ => progress autounfold - | _ => progress (autorewrite with uncps push_id push_basesystem_eval in * ) - | _ => (rewrite uweight_0 in * ) - | _ => assert (p = 0) by omega; subst p; break_match; ring - end. - Qed. - - Lemma small_conditional_sub n (p:T (S n)) (q:T n) - (psmall : small p) (qsmall : small q) : - 0 <= eval p < eval q + uweight bound n -> - small (conditional_sub p q). - Proof. - intros. - cbv [conditional_sub conditional_sub_cps]; autorewrite with uncps push_id. - eapply small_drop_high. - rewrite map2_zselect; break_match; [|assumption]. - eauto using @B.Positional.small_sat_sub with omega. - Qed. - - Lemma eval_scmul n a v : small v -> 0 <= a < bound -> - eval (@scmul n a v) = a * eval v. - Proof. - intro Hsmall. pose_all. apply eval_small in Hsmall. - intros. cbv [scmul scmul_cps eval] in *. repeat autounfold. - autorewrite with uncps. - autorewrite with push_basesystem_eval. - autorewrite with uncps push_id push_basesystem_eval. - rewrite uweight_0, Z.mul_1_l. apply Z.mod_small. - split; [solve[Z.zero_bounds]|]. cbv [uweight] in *. - rewrite !Nat2Z.inj_succ, Z.pow_succ_r by auto using Nat2Z.is_nonneg. - apply Z.mul_lt_mono_nonneg; omega. - Qed. - - Lemma small_scmul n a v : small (@scmul n a v). - Proof. - cbv [scmul scmul_cps eval] in *. repeat autounfold. - autorewrite with uncps push_id push_basesystem_eval. - apply small_compact. - Qed. - - (* TODO : move to tuple *) - Lemma from_list_tl {A n} (ls : list A) H H': - from_list n (List.tl ls) H = tl (from_list (S n) ls H'). - Proof. - induction ls; distr_length. simpl List.tl. - rewrite from_list_cons, tl_append, <-!(from_list_default_eq a ls). - reflexivity. - Qed. - - Lemma eval_div n p : small p -> eval (fst (@divmod n p)) = eval p / bound. - Proof. - cbv [divmod divmod_cps eval]. intros. - autorewrite with uncps push_id cancel_pair. - rewrite (subst_append p) at 2. - rewrite uweight_eval_step. rewrite hd_append, tl_append. - rewrite Z.div_add' by omega. rewrite Z.div_small by auto using small_hd. - ring. - Qed. - - Lemma eval_mod n p : small p -> snd (@divmod n p) = eval p mod bound. - Proof. - cbv [divmod divmod_cps eval]. intros. - autorewrite with uncps push_id cancel_pair. - rewrite (subst_append p) at 2. - rewrite uweight_eval_step, Z.mod_add'_full, hd_append. - rewrite Z.mod_small by auto using small_hd. reflexivity. - Qed. - - Lemma small_div n v : small v -> small (fst (@divmod n v)). - Proof. - cbv [divmod divmod_cps]. intros. - autorewrite with uncps push_id cancel_pair. - auto using small_tl. - Qed. - End Proofs. -End API. -Hint Rewrite nonzero_id join0_id divmod_id drop_high_id scmul_id add_id add_S1_id add_S2_id sub_then_maybe_add_id conditional_sub_id : uncps. - -Hint Unfold - nonzero_cps - nonzero - scmul_cps - scmul - add_cps - add - add_S1_cps - add_S1 - add_S2_cps - add_S2 - sub_then_maybe_add_cps - sub_then_maybe_add - conditional_sub_cps - conditional_sub - eval - encode - : basesystem_partial_evaluation_unfolder. - -Ltac basesystem_partial_evaluation_unfolder t := - let t := (eval cbv delta [ - nonzero_cps - nonzero - scmul_cps - scmul - add_cps - add - add_S1_cps - add_S1 - add_S2_cps - add_S2 - sub_then_maybe_add_cps - sub_then_maybe_add - conditional_sub_cps - conditional_sub - eval - encode - ] in t) in - let t := Saturated.AddSub.basesystem_partial_evaluation_unfolder t in - let t := Saturated.Wrappers.basesystem_partial_evaluation_unfolder t in - let t := Saturated.Core.basesystem_partial_evaluation_unfolder t in - let t := Arithmetic.Core.basesystem_partial_evaluation_unfolder t in - t. - -Ltac Arithmetic.Core.basesystem_partial_evaluation_default_unfolder t ::= - basesystem_partial_evaluation_unfolder t. |