aboutsummaryrefslogtreecommitdiff
path: root/theories/Ints/num
diff options
context:
space:
mode:
Diffstat (limited to 'theories/Ints/num')
-rw-r--r--theories/Ints/num/Basic_type.v64
-rw-r--r--theories/Ints/num/GenAdd.v315
-rw-r--r--theories/Ints/num/GenBase.v377
-rw-r--r--theories/Ints/num/GenDiv.v1438
-rw-r--r--theories/Ints/num/GenDivn1.v489
-rw-r--r--theories/Ints/num/GenLift.v278
-rw-r--r--theories/Ints/num/GenMul.v623
-rw-r--r--theories/Ints/num/GenSqrt.v1312
-rw-r--r--theories/Ints/num/GenSub.v354
-rw-r--r--theories/Ints/num/NMake.v3473
-rw-r--r--theories/Ints/num/Nbasic.v147
-rw-r--r--theories/Ints/num/QMake.v899
-rw-r--r--theories/Ints/num/ZMake.v224
-rw-r--r--theories/Ints/num/Zn2Z.v735
-rw-r--r--theories/Ints/num/ZnZ.v300
-rw-r--r--theories/Ints/num/genN.ml816
16 files changed, 11844 insertions, 0 deletions
diff --git a/theories/Ints/num/Basic_type.v b/theories/Ints/num/Basic_type.v
new file mode 100644
index 0000000000..f481f39427
--- /dev/null
+++ b/theories/Ints/num/Basic_type.v
@@ -0,0 +1,64 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZDivModAux.
+Require Import ZPowerAux.
+
+Open Local Scope Z_scope.
+
+Section Carry.
+
+ Variable A : Set.
+
+ Inductive carry : Set :=
+ | C0 : A -> carry
+ | C1 : A -> carry.
+
+End Carry.
+
+Section Zn2Z.
+
+ Variable znz : Set.
+
+ Inductive zn2z : Set :=
+ | W0 : zn2z
+ | WW : znz -> znz -> zn2z.
+
+ Definition zn2z_to_Z (wB:Z) (w_to_Z:znz->Z) (x:zn2z) :=
+ match x with
+ | W0 => 0
+ | WW xh xl => w_to_Z xh * wB + w_to_Z xl
+ end.
+
+ Definition base digits := Zpower 2 (Zpos digits).
+
+ Definition interp_carry sign B (interp:znz -> Z) c :=
+ match c with
+ | C0 x => interp x
+ | C1 x => sign*B + interp x
+ end.
+
+End Zn2Z.
+
+Implicit Arguments W0 [znz].
+
+Fixpoint word_tr (w:Set) (n:nat) {struct n} : Set :=
+ match n with
+ | O => w
+ | S n => word_tr (zn2z w) n
+ end.
+
+Fixpoint word (w:Set) (n:nat) {struct n} : Set :=
+ match n with
+ | O => w
+ | S n => zn2z (word w n)
+ end.
+
diff --git a/theories/Ints/num/GenAdd.v b/theories/Ints/num/GenAdd.v
new file mode 100644
index 0000000000..9d4c579020
--- /dev/null
+++ b/theories/Ints/num/GenAdd.v
@@ -0,0 +1,315 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section GenAdd.
+ Variable w : Set.
+ Variable w_0 : w.
+ Variable w_1 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_W0 : w -> zn2z w.
+ Variable ww_1 : zn2z w.
+ Variable w_succ_c : w -> carry w.
+ Variable w_add_c : w -> w -> carry w.
+ Variable w_add_carry_c : w -> w -> carry w.
+ Variable w_succ : w -> w.
+ Variable w_add : w -> w -> w.
+ Variable w_add_carry : w -> w -> w.
+
+ Definition ww_succ_c x :=
+ match x with
+ | W0 => C0 ww_1
+ | WW xh xl =>
+ match w_succ_c xl with
+ | C0 l => C0 (WW xh l)
+ | C1 l =>
+ match w_succ_c xh with
+ | C0 h => C0 (WW h w_0)
+ | C1 h => C1 W0
+ end
+ end
+ end.
+
+ Definition ww_succ x :=
+ match x with
+ | W0 => ww_1
+ | WW xh xl =>
+ match w_succ_c xl with
+ | C0 l => WW xh l
+ | C1 l => w_W0 (w_succ xh)
+ end
+ end.
+
+ Definition ww_add_c x y :=
+ match x, y with
+ | W0, _ => C0 y
+ | _, W0 => C0 x
+ | WW xh xl, WW yh yl =>
+ match w_add_c xl yl with
+ | C0 l =>
+ match w_add_c xh yh with
+ | C0 h => C0 (WW h l)
+ | C1 h => C1 (w_WW h l)
+ end
+ | C1 l =>
+ match w_add_carry_c xh yh with
+ | C0 h => C0 (WW h l)
+ | C1 h => C1 (w_WW h l)
+ end
+ end
+ end.
+
+ Variable R : Set.
+ Variable f0 f1 : zn2z w -> R.
+
+ Definition ww_add_c_cont x y :=
+ match x, y with
+ | W0, _ => f0 y
+ | _, W0 => f0 x
+ | WW xh xl, WW yh yl =>
+ match w_add_c xl yl with
+ | C0 l =>
+ match w_add_c xh yh with
+ | C0 h => f0 (WW h l)
+ | C1 h => f1 (w_WW h l)
+ end
+ | C1 l =>
+ match w_add_carry_c xh yh with
+ | C0 h => f0 (WW h l)
+ | C1 h => f1 (w_WW h l)
+ end
+ end
+ end.
+
+ (* ww_add et ww_add_carry conserve la forme normale s'il n'y a pas
+ de debordement *)
+ Definition ww_add x y :=
+ match x, y with
+ | W0, _ => y
+ | _, W0 => x
+ | WW xh xl, WW yh yl =>
+ match w_add_c xl yl with
+ | C0 l => WW (w_add xh yh) l
+ | C1 l => WW (w_add_carry xh yh) l
+ end
+ end.
+
+ Definition ww_add_carry_c x y :=
+ match x, y with
+ | W0, W0 => C0 ww_1
+ | W0, WW yh yl => ww_succ_c (WW yh yl)
+ | WW xh xl, W0 => ww_succ_c (WW xh xl)
+ | WW xh xl, WW yh yl =>
+ match w_add_carry_c xl yl with
+ | C0 l =>
+ match w_add_c xh yh with
+ | C0 h => C0 (WW h l)
+ | C1 h => C1 (WW h l)
+ end
+ | C1 l =>
+ match w_add_carry_c xh yh with
+ | C0 h => C0 (WW h l)
+ | C1 h => C1 (w_WW h l)
+ end
+ end
+ end.
+
+ Definition ww_add_carry x y :=
+ match x, y with
+ | W0, W0 => ww_1
+ | W0, WW yh yl => ww_succ (WW yh yl)
+ | WW xh xl, W0 => ww_succ (WW xh xl)
+ | WW xh xl, WW yh yl =>
+ match w_add_carry_c xl yl with
+ | C0 l => WW (w_add xh yh) l
+ | C1 l => WW (w_add_carry xh yh) l
+ end
+ end.
+
+ (*Section GenProof.*)
+ Variable w_digits : positive.
+ Variable w_to_Z : w -> Z.
+
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[+| c |]" :=
+ (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Notation "[+[ c ]]" :=
+ (interp_carry 1 wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_1 : [|w_1|] = 1.
+ Variable spec_ww_1 : [[ww_1]] = 1.
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_w_W0 : forall h, [[w_W0 h]] = [|h|] * wB.
+ Variable spec_w_succ_c : forall x, [+|w_succ_c x|] = [|x|] + 1.
+ Variable spec_w_add_c : forall x y, [+|w_add_c x y|] = [|x|] + [|y|].
+ Variable spec_w_add_carry_c :
+ forall x y, [+|w_add_carry_c x y|] = [|x|] + [|y|] + 1.
+ Variable spec_w_succ : forall x, [|w_succ x|] = ([|x|] + 1) mod wB.
+ Variable spec_w_add : forall x y, [|w_add x y|] = ([|x|] + [|y|]) mod wB.
+ Variable spec_w_add_carry :
+ forall x y, [|w_add_carry x y|] = ([|x|] + [|y|] + 1) mod wB.
+
+ Lemma spec_ww_succ_c : forall x, [+[ww_succ_c x]] = [[x]] + 1.
+ Proof.
+ destruct x as [ |xh xl];simpl. apply spec_ww_1.
+ generalize (spec_w_succ_c xl);destruct (w_succ_c xl) as [l|l];
+ intro H;unfold interp_carry in H. simpl;rewrite H;ring.
+ rewrite <- Zplus_assoc;rewrite <- H;rewrite Zmult_1_l.
+ assert ([|l|] = 0). generalize (spec_to_Z xl)(spec_to_Z l);omega.
+ rewrite H0;generalize (spec_w_succ_c xh);destruct (w_succ_c xh) as [h|h];
+ intro H1;unfold interp_carry in H1.
+ simpl;rewrite H1;rewrite spec_w_0;ring.
+ unfold interp_carry;simpl ww_to_Z;rewrite wwB_wBwB.
+ assert ([|xh|] = wB - 1). generalize (spec_to_Z xh)(spec_to_Z h);omega.
+ rewrite H2;ring.
+ Qed.
+
+ Lemma spec_ww_add_c : forall x y, [+[ww_add_c x y]] = [[x]] + [[y]].
+ Proof.
+ destruct x as [ |xh xl];simpl;trivial.
+ destruct y as [ |yh yl];simpl. rewrite Zplus_0_r;trivial.
+ replace ([|xh|] * wB + [|xl|] + ([|yh|] * wB + [|yl|]))
+ with (([|xh|]+[|yh|])*wB + ([|xl|]+[|yl|])). 2:ring.
+ generalize (spec_w_add_c xl yl);destruct (w_add_c xl yl) as [l|l];
+ intros H;unfold interp_carry in H;rewrite <- H.
+ generalize (spec_w_add_c xh yh);destruct (w_add_c xh yh) as [h|h];
+ intros H1;unfold interp_carry in *;rewrite <- H1. trivial.
+ repeat rewrite Zmult_1_l;rewrite spec_w_WW;rewrite wwB_wBwB; ring.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ generalize (spec_w_add_carry_c xh yh);destruct (w_add_carry_c xh yh)
+ as [h|h]; intros H1;unfold interp_carry in *;rewrite <- H1.
+ simpl;ring.
+ repeat rewrite Zmult_1_l;rewrite wwB_wBwB;rewrite spec_w_WW;ring.
+ Qed.
+
+ Section Cont.
+ Variable P : zn2z w -> zn2z w -> R -> Prop.
+ Variable x y : zn2z w.
+ Variable spec_f0 : forall r, [[r]] = [[x]] + [[y]] -> P x y (f0 r).
+ Variable spec_f1 : forall r, wwB + [[r]] = [[x]] + [[y]] -> P x y (f1 r).
+
+ Lemma spec_ww_add_c_cont : P x y (ww_add_c_cont x y).
+ Proof.
+ destruct x as [ |xh xl];simpl;trivial.
+ apply spec_f0;trivial.
+ destruct y as [ |yh yl];simpl.
+ apply spec_f0;simpl;rewrite Zplus_0_r;trivial.
+ generalize (spec_w_add_c xl yl);destruct (w_add_c xl yl) as [l|l];
+ intros H;unfold interp_carry in H.
+ generalize (spec_w_add_c xh yh);destruct (w_add_c xh yh) as [h|h];
+ intros H1;unfold interp_carry in *.
+ apply spec_f0. simpl;rewrite H;rewrite H1;ring.
+ apply spec_f1. simpl;rewrite spec_w_WW;rewrite H.
+ rewrite Zplus_assoc;rewrite wwB_wBwB. rewrite Zpower_2; rewrite <- Zmult_plus_distr_l.
+ rewrite Zmult_1_l in H1;rewrite H1;ring.
+ generalize (spec_w_add_carry_c xh yh);destruct (w_add_carry_c xh yh)
+ as [h|h]; intros H1;unfold interp_carry in *.
+ apply spec_f0;simpl;rewrite H1. rewrite Zmult_plus_distr_l.
+ rewrite <- Zplus_assoc;rewrite H;ring.
+ apply spec_f1. simpl;rewrite spec_w_WW;rewrite wwB_wBwB.
+ rewrite Zplus_assoc; rewrite Zpower_2; rewrite <- Zmult_plus_distr_l.
+ rewrite Zmult_1_l in H1;rewrite H1. rewrite Zmult_plus_distr_l.
+ rewrite <- Zplus_assoc;rewrite H;ring.
+ Qed.
+
+ End Cont.
+
+ Lemma spec_ww_add_carry_c :
+ forall x y, [+[ww_add_carry_c x y]] = [[x]] + [[y]] + 1.
+ Proof.
+ destruct x as [ |xh xl];intro y;simpl.
+ exact (spec_ww_succ_c y).
+ destruct y as [ |yh yl];simpl.
+ rewrite Zplus_0_r;exact (spec_ww_succ_c (WW xh xl)).
+ replace ([|xh|] * wB + [|xl|] + ([|yh|] * wB + [|yl|]) + 1)
+ with (([|xh|]+[|yh|])*wB + ([|xl|]+[|yl|]+1)). 2:ring.
+ generalize (spec_w_add_carry_c xl yl);destruct (w_add_carry_c xl yl)
+ as [l|l];intros H;unfold interp_carry in H;rewrite <- H.
+ generalize (spec_w_add_c xh yh);destruct (w_add_c xh yh) as [h|h];
+ intros H1;unfold interp_carry in H1;rewrite <- H1. trivial.
+ unfold interp_carry;repeat rewrite Zmult_1_l;simpl;rewrite wwB_wBwB;ring.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ generalize (spec_w_add_carry_c xh yh);destruct (w_add_carry_c xh yh)
+ as [h|h];intros H1;unfold interp_carry in H1;rewrite <- H1. trivial.
+ unfold interp_carry;rewrite spec_w_WW;
+ repeat rewrite Zmult_1_l;simpl;rewrite wwB_wBwB;ring.
+ Qed.
+
+ Lemma spec_ww_succ : forall x, [[ww_succ x]] = ([[x]] + 1) mod wwB.
+ Proof.
+ destruct x as [ |xh xl];simpl.
+ rewrite spec_ww_1;rewrite Zmod_def_small;trivial.
+ split;[intro;discriminate|apply wwB_pos].
+ rewrite <- Zplus_assoc;generalize (spec_w_succ_c xl);
+ destruct (w_succ_c xl) as[l|l];intro H;unfold interp_carry in H;rewrite <-H.
+ rewrite Zmod_def_small;trivial.
+ rewrite wwB_wBwB;apply beta_mult;apply spec_to_Z.
+ assert ([|l|] = 0). clear spec_ww_1 spec_w_1 spec_w_0.
+ assert (H1:= spec_to_Z l); assert (H2:= spec_to_Z xl); omega.
+ rewrite H0;rewrite Zplus_0_r;rewrite <- Zmult_plus_distr_l;rewrite wwB_wBwB.
+ rewrite Zpower_2; rewrite Zmult_mod_distr_r;try apply lt_0_wB.
+ rewrite spec_w_W0;rewrite spec_w_succ;trivial.
+ Qed.
+
+ Lemma spec_ww_add : forall x y, [[ww_add x y]] = ([[x]] + [[y]]) mod wwB.
+ Proof.
+ destruct x as [ |xh xl];intros y;simpl.
+ rewrite Zmod_def_small;trivial. apply spec_ww_to_Z;trivial.
+ destruct y as [ |yh yl].
+ change [[W0]] with 0;rewrite Zplus_0_r.
+ rewrite Zmod_def_small;trivial.
+ exact (spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW xh xl)).
+ simpl. replace ([|xh|] * wB + [|xl|] + ([|yh|] * wB + [|yl|]))
+ with (([|xh|]+[|yh|])*wB + ([|xl|]+[|yl|])). 2:ring.
+ generalize (spec_w_add_c xl yl);destruct (w_add_c xl yl) as [l|l];
+ unfold interp_carry;intros H;simpl;rewrite <- H.
+ rewrite (mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_w_add;trivial.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ rewrite(mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_w_add_carry;trivial.
+ Qed.
+
+ Lemma spec_ww_add_carry :
+ forall x y, [[ww_add_carry x y]] = ([[x]] + [[y]] + 1) mod wwB.
+ Proof.
+ destruct x as [ |xh xl];intros y;simpl.
+ exact (spec_ww_succ y).
+ destruct y as [ |yh yl].
+ change [[W0]] with 0;rewrite Zplus_0_r. exact (spec_ww_succ (WW xh xl)).
+ simpl;replace ([|xh|] * wB + [|xl|] + ([|yh|] * wB + [|yl|]) + 1)
+ with (([|xh|]+[|yh|])*wB + ([|xl|]+[|yl|]+1)). 2:ring.
+ generalize (spec_w_add_carry_c xl yl);destruct (w_add_carry_c xl yl)
+ as [l|l];unfold interp_carry;intros H;rewrite <- H;simpl ww_to_Z.
+ rewrite(mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_w_add;trivial.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ rewrite(mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_w_add_carry;trivial.
+ Qed.
+
+(* End GenProof. *)
+End GenAdd.
diff --git a/theories/Ints/num/GenBase.v b/theories/Ints/num/GenBase.v
new file mode 100644
index 0000000000..b953566ede
--- /dev/null
+++ b/theories/Ints/num/GenBase.v
@@ -0,0 +1,377 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import ZPowerAux.
+Require Import Basic_type.
+Require Import JMeq.
+
+Open Local Scope Z_scope.
+
+Section GenBase.
+ Variable w : Set.
+ Variable w_0 : w.
+ Variable w_1 : w.
+ Variable w_Bm1 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_0W : w -> zn2z w.
+ Variable w_digits : positive.
+ Variable w_to_Z : w -> Z.
+ Variable w_compare : w -> w -> comparison.
+
+ Definition ww_digits := xO w_digits.
+
+ Definition ww_to_Z := zn2z_to_Z (base w_digits) w_to_Z.
+
+ Definition ww_1 := WW w_0 w_1.
+
+ Definition ww_Bm1 := WW w_Bm1 w_Bm1.
+
+ Definition ww_WW xh xl : zn2z (zn2z w) :=
+ match xh, xl with
+ | W0, W0 => W0
+ | _, _ => WW xh xl
+ end.
+
+ Definition ww_W0 h : zn2z (zn2z w) :=
+ match h with
+ | W0 => W0
+ | _ => WW h W0
+ end.
+
+ Definition ww_0W l : zn2z (zn2z w) :=
+ match l with
+ | W0 => W0
+ | _ => WW W0 l
+ end.
+
+ Definition gen_WW (n:nat) :=
+ match n return word w n -> word w n -> word w (S n) with
+ | O => w_WW
+ | S n =>
+ fun (h l : zn2z (word w n)) =>
+ match h, l with
+ | W0, W0 => W0
+ | _, _ => WW h l
+ end
+ end.
+
+ Fixpoint gen_digits (n:nat) : positive :=
+ match n with
+ | O => w_digits
+ | S n => xO (gen_digits n)
+ end.
+
+ Definition gen_wB n := base (gen_digits n).
+
+ Fixpoint gen_to_Z (n:nat) : word w n -> Z :=
+ match n return word w n -> Z with
+ | O => w_to_Z
+ | S n => zn2z_to_Z (gen_wB n) (gen_to_Z n)
+ end.
+
+ Fixpoint extend_aux (n:nat) (x:zn2z w) {struct n}: word w (S n) :=
+ match n return word w (S n) with
+ | O => x
+ | S n1 => WW W0 (extend_aux n1 x)
+ end.
+
+ Definition extend (n:nat) (x:w) : word w (S n) :=
+ let r := w_0W x in
+ match r with
+ | W0 => W0
+ | _ => extend_aux n r
+ end.
+
+ Definition gen_0 n : word w n :=
+ match n return word w n with
+ | O => w_0
+ | S _ => W0
+ end.
+
+ Definition gen_split (n:nat) (x:zn2z (word w n)) :=
+ match x with
+ | W0 =>
+ match n return word w n * word w n with
+ | O => (w_0,w_0)
+ | S _ => (W0, W0)
+ end
+ | WW h l => (h,l)
+ end.
+
+ Definition ww_compare x y :=
+ match x, y with
+ | W0, W0 => Eq
+ | W0, WW yh yl =>
+ match w_compare w_0 yh with
+ | Eq => w_compare w_0 yl
+ | _ => Lt
+ end
+ | WW xh xl, W0 =>
+ match w_compare xh w_0 with
+ | Eq => w_compare xl w_0
+ | _ => Gt
+ end
+ | WW xh xl, WW yh yl =>
+ match w_compare xh yh with
+ | Eq => w_compare xl yl
+ | Lt => Lt
+ | Gt => Gt
+ end
+ end.
+
+ Section GenProof.
+ Notation wB := (base w_digits).
+ Notation wwB := (base ww_digits).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[[ x ]]" := (ww_to_Z x) (at level 0, x at level 99).
+ Notation "[+[ c ]]" :=
+ (interp_carry 1 wwB ww_to_Z c) (at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB ww_to_Z c) (at level 0, x at level 99).
+ Notation "[! n | x !]" := (gen_to_Z n x) (at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_1 : [|w_1|] = 1.
+ Variable spec_w_Bm1 : [|w_Bm1|] = wB - 1.
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+ Variable spec_w_compare : forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+
+ Lemma wwB_wBwB : wwB = wB^2.
+ Proof.
+ unfold base, ww_digits;rewrite Zpower_2; rewrite (Zpos_xO w_digits).
+ replace (2 * Zpos w_digits) with (Zpos w_digits + Zpos w_digits).
+ apply Zpower_exp; unfold Zge;simpl;intros;discriminate.
+ ring.
+ Qed.
+
+ Lemma spec_ww_1 : [[ww_1]] = 1.
+ Proof. simpl;rewrite spec_w_0;rewrite spec_w_1;ring. Qed.
+
+ Lemma spec_ww_Bm1 : [[ww_Bm1]] = wwB - 1.
+ Proof. simpl;rewrite spec_w_Bm1;rewrite wwB_wBwB;ring. Qed.
+
+ Lemma lt_0_wB : 0 < wB.
+ Proof.
+ unfold base;apply Zpower_lt_0. unfold Zlt;reflexivity.
+ unfold Zle;intros H;discriminate H.
+ Qed.
+
+ Lemma lt_0_wwB : 0 < wwB.
+ Proof. rewrite wwB_wBwB; rewrite Zpower_2; apply Zmult_lt_0_compat;apply lt_0_wB. Qed.
+
+ Lemma wB_pos: 1 < wB.
+ Proof.
+ unfold base;apply Zlt_le_trans with (2^1). unfold Zlt;reflexivity.
+ apply Zpower_le_monotone. unfold Zlt;reflexivity.
+ split;unfold Zle;intros H. discriminate H.
+ clear spec_w_0W w_0W spec_w_Bm1 spec_to_Z spec_w_WW w_WW.
+ destruct w_digits; discriminate H.
+ Qed.
+
+ Lemma wwB_pos: 1 < wwB.
+ Proof.
+ assert (H:= wB_pos);rewrite wwB_wBwB;rewrite <-(Zmult_1_r 1).
+ rewrite Zpower_2.
+ apply Zmult_lt_compat;(split;[unfold Zlt;reflexivity|trivial]).
+ apply Zlt_le_weak;trivial.
+ Qed.
+
+ Theorem wB_div_2: 2 * (wB / 2) = wB.
+ Proof.
+ clear spec_w_0 w_0 spec_w_1 w_1 spec_w_Bm1 w_Bm1 spec_w_WW spec_w_0W
+ spec_to_Z;unfold base.
+ assert (2 ^ Zpos w_digits = 2 * (2 ^ (Zpos w_digits - 1))).
+ pattern 2 at 2; rewrite <- Zpower_exp_1.
+ rewrite <- Zpower_exp; auto with zarith.
+ eq_tac; auto with zarith.
+ case w_digits; compute; intros; discriminate.
+ rewrite H; eq_tac; auto with zarith.
+ rewrite Zmult_comm; apply Z_div_mult; auto with zarith.
+ Qed.
+
+ Theorem wwB_div_2 : wwB / 2 = wB / 2 * wB.
+ Proof.
+ clear spec_w_0 w_0 spec_w_1 w_1 spec_w_Bm1 w_Bm1 spec_w_WW spec_w_0W
+ spec_to_Z.
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ pattern wB at 1; rewrite <- wB_div_2; auto.
+ rewrite <- Zmult_assoc.
+ repeat (rewrite (Zmult_comm 2); rewrite Z_div_mult); auto with zarith.
+ Qed.
+
+ Lemma mod_wwB : forall z x,
+ (z*wB + [|x|]) mod wwB = (z mod wB)*wB + [|x|].
+ Proof.
+ intros z x.
+ rewrite Zmod_plus. 2:apply lt_0_wwB.
+ pattern wwB at 1;rewrite wwB_wBwB; rewrite Zpower_2.
+ rewrite Zmult_mod_distr_r;try apply lt_0_wB.
+ rewrite (Zmod_def_small [|x|]).
+ apply Zmod_def_small;rewrite wwB_wBwB;apply beta_mult;try apply spec_to_Z.
+ apply Z_mod_lt;apply Zlt_gt;apply lt_0_wB.
+ destruct (spec_to_Z x);split;trivial.
+ change [|x|] with (0*wB+[|x|]). rewrite wwB_wBwB.
+ rewrite Zpower_2;rewrite <- (Zplus_0_r (wB*wB));apply beta_lex_inv.
+ apply lt_0_wB. apply spec_to_Z. split;[apply Zle_refl | apply lt_0_wB].
+ Qed.
+
+ Lemma wB_div : forall x y, ([|x|] * wB + [|y|]) / wB = [|x|].
+ Proof.
+ clear spec_w_0 spec_w_1 spec_w_Bm1 w_0 w_1 w_Bm1.
+ intros x y;unfold base;rewrite Zdiv_shift_r;auto with zarith.
+ rewrite Z_div_mult;auto with zarith.
+ destruct (spec_to_Z x);trivial.
+ Qed.
+
+ Lemma wB_div_plus : forall x y p,
+ 0 <= p ->
+ ([|x|]*wB + [|y|]) / 2^(Zpos w_digits + p) = [|x|] / 2^p.
+ Proof.
+ clear spec_w_0 spec_w_1 spec_w_Bm1 w_0 w_1 w_Bm1.
+ intros x y p Hp;rewrite Zpower_exp;auto with zarith.
+ rewrite <- Zdiv_Zdiv;auto with zarith.
+ rewrite wB_div;trivial.
+ Qed.
+
+ Lemma lt_wB_wwB : wB < wwB.
+ Proof.
+ clear spec_w_0 spec_w_1 spec_w_Bm1 w_0 w_1 w_Bm1.
+ unfold base;apply Zpower_lt_monotone;auto with zarith.
+ assert (0 < Zpos w_digits). compute;reflexivity.
+ unfold ww_digits;rewrite Zpos_xO;auto with zarith.
+ Qed.
+
+ Lemma w_to_Z_wwB : forall x, x < wB -> x < wwB.
+ Proof.
+ intros x H;apply Zlt_trans with wB;trivial;apply lt_wB_wwB.
+ Qed.
+
+ Lemma spec_ww_to_Z : forall x, 0 <= [[x]] < wwB.
+ Proof.
+ clear spec_w_0 spec_w_1 spec_w_Bm1 w_0 w_1 w_Bm1.
+ destruct x as [ |h l];simpl.
+ split;[apply Zle_refl|apply lt_0_wwB].
+ assert (H:=spec_to_Z h);assert (L:=spec_to_Z l);split.
+ apply Zplus_le_0_compat;auto with zarith.
+ rewrite <- (Zplus_0_r wwB);rewrite wwB_wBwB; rewrite Zpower_2;
+ apply beta_lex_inv;auto with zarith.
+ Qed.
+
+ Lemma gen_wB_wwB : forall n, gen_wB n * gen_wB n = gen_wB (S n).
+ Proof.
+ intros n;unfold gen_wB;simpl.
+ unfold base;rewrite (Zpos_xO (gen_digits n)).
+ replace (2 * Zpos (gen_digits n)) with
+ (Zpos (gen_digits n) + Zpos (gen_digits n)).
+ symmetry; apply Zpower_exp;intro;discriminate.
+ ring.
+ Qed.
+
+ Lemma spec_gen_to_Z :
+ forall n (x:word w n), 0 <= gen_to_Z n x < gen_wB n.
+ Proof.
+ clear spec_w_0 spec_w_1 spec_w_Bm1 w_0 w_1 w_Bm1.
+ induction n;intros. exact (spec_to_Z x).
+ unfold gen_to_Z;fold gen_to_Z.
+ destruct x;unfold zn2z_to_Z.
+ unfold gen_wB,base;split;auto with zarith.
+ assert (U0:= IHn w0);assert (U1:= IHn w1).
+ split;auto with zarith.
+ apply Zlt_le_trans with ((gen_wB n - 1) * gen_wB n + gen_wB n).
+ assert (gen_to_Z n w0*gen_wB n <= (gen_wB n - 1)*gen_wB n).
+ apply Zmult_le_compat_r;auto with zarith.
+ auto with zarith.
+ rewrite <- gen_wB_wwB.
+ replace ((gen_wB n - 1) * gen_wB n + gen_wB n) with (gen_wB n * gen_wB n);
+ [auto with zarith | ring].
+ Qed.
+
+ Lemma spec_gen_WW : forall n (h l : word w n),
+ [!S n|gen_WW n h l!] = [!n|h!] * gen_wB n + [!n|l!].
+ Proof.
+ induction n;simpl;intros;trivial.
+ destruct h;auto.
+ destruct l;auto.
+ Qed.
+
+ Lemma spec_extend_aux : forall n x, [!S n|extend_aux n x!] = [[x]].
+ Proof. induction n;simpl;trivial. Qed.
+
+ Lemma spec_extend : forall n x, [!S n|extend n x!] = [|x|].
+ Proof.
+ intros n x;assert (H:= spec_w_0W x);unfold extend.
+ destruct (w_0W x);simpl;trivial.
+ rewrite <- H;exact (spec_extend_aux n (WW w0 w1)).
+ Qed.
+
+ Lemma spec_gen_0 : forall n, [!n|gen_0 n!] = 0.
+ Proof. destruct n;trivial. Qed.
+
+ Lemma spec_gen_split : forall n x,
+ let (h,l) := gen_split n x in
+ [!S n|x!] = [!n|h!] * gen_wB n + [!n|l!].
+ Proof.
+ destruct x;simpl;auto.
+ destruct n;simpl;trivial.
+ rewrite spec_w_0;trivial.
+ Qed.
+
+ Lemma wB_lex_inv: forall a b c d,
+ a < c ->
+ a * wB + [|b|] < c * wB + [|d|].
+ Proof.
+ intros a b c d H1; apply beta_lex_inv with (1 := H1); auto.
+ Qed.
+
+ Lemma spec_ww_compare : forall x y,
+ match ww_compare x y with
+ | Eq => [[x]] = [[y]]
+ | Lt => [[x]] < [[y]]
+ | Gt => [[x]] > [[y]]
+ end.
+ Proof.
+ destruct x as [ |xh xl];destruct y as [ |yh yl];simpl;trivial.
+ generalize (spec_w_compare w_0 yh);destruct (w_compare w_0 yh);
+ intros H;rewrite spec_w_0 in H.
+ rewrite <- H;simpl;rewrite <- spec_w_0;apply spec_w_compare.
+ change 0 with (0*wB+0);pattern 0 at 2;rewrite <- spec_w_0.
+ apply wB_lex_inv;trivial.
+ absurd (0 <= [|yh|]). apply Zgt_not_le;trivial.
+ destruct (spec_to_Z yh);trivial.
+ generalize (spec_w_compare xh w_0);destruct (w_compare xh w_0);
+ intros H;rewrite spec_w_0 in H.
+ rewrite H;simpl;rewrite <- spec_w_0;apply spec_w_compare.
+ absurd (0 <= [|xh|]). apply Zgt_not_le;apply Zlt_gt;trivial.
+ destruct (spec_to_Z xh);trivial.
+ apply Zlt_gt;change 0 with (0*wB+0);pattern 0 at 2;rewrite <- spec_w_0.
+ apply wB_lex_inv;apply Zgt_lt;trivial.
+
+ generalize (spec_w_compare xh yh);destruct (w_compare xh yh);intros H.
+ rewrite H;generalize (spec_w_compare xl yl);destruct (w_compare xl yl);
+ intros H1;[rewrite H1|apply Zplus_lt_compat_l|apply Zplus_gt_compat_l];
+ trivial.
+ apply wB_lex_inv;trivial.
+ apply Zlt_gt;apply wB_lex_inv;apply Zgt_lt;trivial.
+ Qed.
+
+ End GenProof.
+
+End GenBase.
+
diff --git a/theories/Ints/num/GenDiv.v b/theories/Ints/num/GenDiv.v
new file mode 100644
index 0000000000..4bcea709d0
--- /dev/null
+++ b/theories/Ints/num/GenDiv.v
@@ -0,0 +1,1438 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import ZPowerAux.
+Require Import Basic_type.
+Require Import GenBase.
+Require Import GenDivn1.
+Require Import GenAdd.
+Require Import GenSub.
+
+Open Local Scope Z_scope.
+
+Ltac zarith := auto with zarith.
+
+
+Section POS_MOD.
+
+ Variable w:Set.
+ Variable w_0 : w.
+ Variable w_digits : positive.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_pos_mod : positive -> w -> w.
+
+ Definition ww_pos_mod p x :=
+ match x with
+ | W0 => W0
+ | WW xh xl =>
+ match Pcompare p w_digits Eq with
+ | Eq => w_WW w_0 xl
+ | Lt => w_WW w_0 (w_pos_mod p xl)
+ | Gt =>
+ let n := Pminus p w_digits in
+ w_WW (w_pos_mod n xh) xl
+ end
+ end.
+
+
+ Variable w_to_Z : w -> Z.
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+
+
+ Variable spec_w_0 : [|w_0|] = 0.
+
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+
+ Variable spec_pos_mod : forall w p,
+ [|w_pos_mod p w|] = [|w|] mod (2 ^ Zpos p).
+
+ Hint Rewrite spec_w_0 spec_w_WW : w_rewrite.
+
+ Lemma spec_ww_pos_mod : forall w p,
+ [[ww_pos_mod p w]] = [[w]] mod (2 ^ Zpos p).
+ assert (HHHHH:= lt_0_wB w_digits).
+ assert (F0: forall x y, x - y + y = x); auto with zarith.
+ intros w1 p; unfold ww_pos_mod; case w1.
+ autorewrite with w_rewrite; rewrite Zmod_def_small; auto with zarith.
+ match goal with |- context [(?X ?= ?Y)%positive Eq] =>
+ case_eq (Pcompare X Y Eq) end; intros H1.
+ assert (E1: Zpos p = Zpos w_digits); auto.
+ rewrite Pcompare_Eq_eq with (1:= H1); auto with zarith.
+ rewrite E1.
+ intros xh xl; simpl ww_to_Z;autorewrite with w_rewrite rm10.
+ match goal with |- context id [2 ^Zpos w_digits] =>
+ let v := context id [wB] in change v
+ end.
+ rewrite Zmod_plus; auto with zarith.
+ rewrite Zmod_mult_0; auto with zarith.
+ autorewrite with rm10.
+ rewrite Zmod_mod; auto with zarith.
+ rewrite Zmod_def_small; auto with zarith.
+ assert (Eq1: Zpos p < Zpos w_digits); auto.
+ intros xh xl; autorewrite with w_rewrite rm10.
+ rewrite spec_pos_mod; auto with zarith.
+ assert (Eq2: Zpos p+(Zpos w_digits -Zpos p) = Zpos w_digits);auto with zarith.
+ simpl ww_to_Z;unfold base; rewrite <- Eq2.
+ rewrite Zpower_exp; auto with zarith.
+ rewrite (fun x => (Zmult_comm (2 ^ x))); rewrite Zmult_assoc.
+ rewrite Zmod_plus; auto with zarith.
+ rewrite Zmod_mult_0; auto with zarith.
+ autorewrite with rm10.
+ rewrite Zmod_mod; auto with zarith.
+ assert (Eq1: Zpos p > Zpos w_digits); auto.
+ intros xh xl; autorewrite with w_rewrite rm10.
+ rewrite spec_pos_mod; auto with zarith.
+ simpl ww_to_Z.
+ pattern [|xh|] at 2; rewrite Z_div_mod_eq with (b := 2 ^ Zpos (p - w_digits));
+ auto with zarith.
+ rewrite (fun x => (Zmult_comm (2 ^ x))); rewrite Zmult_plus_distr_l.
+ unfold base; rewrite <- Zmult_assoc; rewrite <- Zpower_exp;
+ auto with zarith.
+ rewrite Zpos_minus; auto with zarith.
+ rewrite F0; auto with zarith.
+ rewrite <- Zplus_assoc; rewrite Zmod_plus; auto with zarith.
+ rewrite Zmod_mult_0; auto with zarith.
+ autorewrite with rm10.
+ rewrite Zmod_mod; auto with zarith.
+ apply sym_equal; apply Zmod_def_small; auto with zarith.
+ case (spec_to_Z xh); intros U1 U2.
+ case (spec_to_Z xl); intros U3 U4.
+ split; auto with zarith.
+ apply Zplus_le_0_compat; auto with zarith.
+ apply Zmult_le_0_compat; auto with zarith.
+ match goal with |- 0 <= ?X mod ?Y =>
+ case (Z_mod_lt X Y); auto with zarith
+ end.
+ match goal with |- ?X mod ?Y * ?U + ?Z < ?T =>
+ apply Zle_lt_trans with ((Y - 1) * U + Z );
+ [case (Z_mod_lt X Y); auto with zarith | idtac]
+ end.
+ match goal with |- ?X * ?U + ?Y < ?Z =>
+ apply Zle_lt_trans with (X * U + (U - 1))
+ end.
+ apply Zplus_le_compat_l; auto with zarith.
+ case (spec_to_Z xl); unfold base; auto with zarith.
+ rewrite Zmult_minus_distr_r; rewrite <- Zpower_exp; auto with zarith.
+ rewrite F0; auto with zarith.
+ Qed.
+
+End POS_MOD.
+
+Section GenDiv32.
+
+ Variable w : Set.
+ Variable w_0 : w.
+ Variable w_Bm1 : w.
+ Variable w_Bm2 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_compare : w -> w -> comparison.
+ Variable w_add_c : w -> w -> carry w.
+ Variable w_add_carry_c : w -> w -> carry w.
+ Variable w_add : w -> w -> w.
+ Variable w_add_carry : w -> w -> w.
+ Variable w_pred : w -> w.
+ Variable w_sub : w -> w -> w.
+ Variable w_mul_c : w -> w -> zn2z w.
+ Variable w_div21 : w -> w -> w -> w*w.
+ Variable ww_sub_c : zn2z w -> zn2z w -> carry (zn2z w).
+
+ Definition w_div32 a1 a2 a3 b1 b2 :=
+ Eval lazy beta iota delta [ww_add_c_cont ww_add] in
+ match w_compare a1 b1 with
+ | Lt =>
+ let (q,r) := w_div21 a1 a2 b1 in
+ match ww_sub_c (w_WW r a3) (w_mul_c q b2) with
+ | C0 r1 => (q,r1)
+ | C1 r1 =>
+ let q := w_pred q in
+ ww_add_c_cont w_WW w_add_c w_add_carry_c
+ (fun r2=>(w_pred q, ww_add w_add_c w_add w_add_carry r2 (WW b1 b2)))
+ (fun r2 => (q,r2))
+ r1 (WW b1 b2)
+ end
+ | Eq =>
+ ww_add_c_cont w_WW w_add_c w_add_carry_c
+ (fun r => (w_Bm2, ww_add w_add_c w_add w_add_carry r (WW b1 b2)))
+ (fun r => (w_Bm1,r))
+ (WW (w_sub a2 b2) a3) (WW b1 b2)
+ | Gt => (w_0, W0) (* cas absurde *)
+ end.
+
+ (* Proof *)
+
+ Variable w_digits : positive.
+ Variable w_to_Z : w -> Z.
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[+| c |]" :=
+ (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_Bm1 : [|w_Bm1|] = wB - 1.
+ Variable spec_w_Bm2 : [|w_Bm2|] = wB - 2.
+
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_compare :
+ forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Variable spec_w_add_c : forall x y, [+|w_add_c x y|] = [|x|] + [|y|].
+ Variable spec_w_add_carry_c :
+ forall x y, [+|w_add_carry_c x y|] = [|x|] + [|y|] + 1.
+
+ Variable spec_w_add : forall x y, [|w_add x y|] = ([|x|] + [|y|]) mod wB.
+ Variable spec_w_add_carry :
+ forall x y, [|w_add_carry x y|] = ([|x|] + [|y|] + 1) mod wB.
+
+ Variable spec_pred : forall x, [|w_pred x|] = ([|x|] - 1) mod wB.
+ Variable spec_sub : forall x y, [|w_sub x y|] = ([|x|] - [|y|]) mod wB.
+
+ Variable spec_mul_c : forall x y, [[ w_mul_c x y ]] = [|x|] * [|y|].
+ Variable spec_div21 : forall a1 a2 b,
+ wB/2 <= [|b|] ->
+ [|a1|] < [|b|] ->
+ let (q,r) := w_div21 a1 a2 b in
+ [|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+
+ Variable spec_ww_sub_c : forall x y, [-[ww_sub_c x y]] = [[x]] - [[y]].
+
+ Ltac Spec_w_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_to_Z x).
+ Ltac Spec_ww_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_ww_to_Z w_digits w_to_Z spec_to_Z x).
+
+ Theorem wB_div2: forall x, wB/2 <= x -> wB <= 2 * x.
+ intros x H; rewrite <- wB_div_2; apply Zmult_le_compat_l; auto with zarith.
+ Qed.
+
+ Lemma Zmult_lt_0_reg_r_2 : forall n m : Z, 0 <= n -> 0 < m * n -> 0 < m.
+ Proof.
+ intros n m H1 H2;apply Zmult_lt_0_reg_r with n;trivial.
+ destruct (Zle_lt_or_eq _ _ H1);trivial.
+ subst;rewrite Zmult_0_r in H2;discriminate H2.
+ Qed.
+
+ Theorem spec_w_div32 : forall a1 a2 a3 b1 b2,
+ wB/2 <= [|b1|] ->
+ [[WW a1 a2]] < [[WW b1 b2]] ->
+ let (q,r) := w_div32 a1 a2 a3 b1 b2 in
+ [|a1|] * wwB + [|a2|] * wB + [|a3|] =
+ [|q|] * ([|b1|] * wB + [|b2|]) + [[r]] /\
+ 0 <= [[r]] < [|b1|] * wB + [|b2|].
+ Proof.
+ intros a1 a2 a3 b1 b2 Hle Hlt.
+ assert (U:= lt_0_wB w_digits); assert (U1:= lt_0_wwB w_digits).
+ Spec_w_to_Z a1;Spec_w_to_Z a2;Spec_w_to_Z a3;Spec_w_to_Z b1;Spec_w_to_Z b2.
+ rewrite wwB_wBwB; rewrite Zpower_2; rewrite Zmult_assoc;rewrite <- Zmult_plus_distr_l.
+ change (w_div32 a1 a2 a3 b1 b2) with
+ match w_compare a1 b1 with
+ | Lt =>
+ let (q,r) := w_div21 a1 a2 b1 in
+ match ww_sub_c (w_WW r a3) (w_mul_c q b2) with
+ | C0 r1 => (q,r1)
+ | C1 r1 =>
+ let q := w_pred q in
+ ww_add_c_cont w_WW w_add_c w_add_carry_c
+ (fun r2=>(w_pred q, ww_add w_add_c w_add w_add_carry r2 (WW b1 b2)))
+ (fun r2 => (q,r2))
+ r1 (WW b1 b2)
+ end
+ | Eq =>
+ ww_add_c_cont w_WW w_add_c w_add_carry_c
+ (fun r => (w_Bm2, ww_add w_add_c w_add w_add_carry r (WW b1 b2)))
+ (fun r => (w_Bm1,r))
+ (WW (w_sub a2 b2) a3) (WW b1 b2)
+ | Gt => (w_0, W0) (* cas absurde *)
+ end.
+ assert (Hcmp:=spec_compare a1 b1);destruct (w_compare a1 b1).
+ simpl in Hlt.
+ rewrite Hcmp in Hlt;assert ([|a2|] < [|b2|]). omega.
+ assert ([[WW (w_sub a2 b2) a3]] = ([|a2|]-[|b2|])*wB + [|a3|] + wwB).
+ simpl;rewrite spec_sub.
+ assert ([|a2|] - [|b2|] = wB*(-1) + ([|a2|] - [|b2|] + wB)). ring.
+ assert (0 <= [|a2|] - [|b2|] + wB < wB). omega.
+ rewrite <-(Zmod_unique ([|a2|]-[|b2|]) wB (-1) ([|a2|]-[|b2|]+wB) U H1 H0).
+ rewrite wwB_wBwB;ring.
+ assert (U2 := wB_pos w_digits).
+ eapply spec_ww_add_c_cont with (P :=
+ fun (x y:zn2z w) (res:w*zn2z w) =>
+ let (q, r) := res in
+ ([|a1|] * wB + [|a2|]) * wB + [|a3|] =
+ [|q|] * ([|b1|] * wB + [|b2|]) + [[r]] /\
+ 0 <= [[r]] < [|b1|] * wB + [|b2|]);eauto.
+ rewrite H0;intros r.
+ repeat
+ (rewrite spec_ww_add;eauto || rewrite spec_w_Bm1 || rewrite spec_w_Bm2);
+ simpl ww_to_Z;try rewrite Zmult_1_l;intros H1.
+ assert (0<= ([[r]] + ([|b1|] * wB + [|b2|])) - wwB < [|b1|] * wB + [|b2|]).
+ Spec_ww_to_Z r;split;zarith.
+ rewrite H1.
+ assert (H12:= wB_div2 Hle). assert (wwB <= 2 * [|b1|] * wB).
+ rewrite wwB_wBwB; rewrite Zpower_2; zarith.
+ assert (-wwB < ([|a2|] - [|b2|]) * wB + [|a3|] < 0).
+ split. apply Zlt_le_trans with (([|a2|] - [|b2|]) * wB);zarith.
+ rewrite wwB_wBwB;replace (-(wB^2)) with (-wB*wB);[zarith | ring].
+ apply Zmult_lt_compat_r;zarith.
+ apply Zle_lt_trans with (([|a2|] - [|b2|]) * wB + (wB -1));zarith.
+ replace ( ([|a2|] - [|b2|]) * wB + (wB - 1)) with
+ (([|a2|] - [|b2|] + 1) * wB + - 1);[zarith | ring].
+ assert (([|a2|] - [|b2|] + 1) * wB <= 0);zarith.
+ replace 0 with (0*wB);zarith.
+ replace (([|a2|] - [|b2|]) * wB + [|a3|] + wwB + ([|b1|] * wB + [|b2|]) +
+ ([|b1|] * wB + [|b2|]) - wwB) with
+ (([|a2|] - [|b2|]) * wB + [|a3|] + 2*[|b1|] * wB + 2*[|b2|]);
+ [zarith | ring].
+ rewrite <- (Zmod_unique ([[r]] + ([|b1|] * wB + [|b2|])) wwB
+ 1 ([[r]] + ([|b1|] * wB + [|b2|]) - wwB));zarith;try (ring;fail).
+ split. rewrite H1;rewrite Hcmp;ring. trivial.
+ Spec_ww_to_Z (WW b1 b2). simpl in HH4;zarith.
+ rewrite H0;intros r;repeat
+ (rewrite spec_w_Bm1 || rewrite spec_w_Bm2);
+ simpl ww_to_Z;try rewrite Zmult_1_l;intros H1.
+ assert ([[r]]=([|a2|]-[|b2|])*wB+[|a3|]+([|b1|]*wB+[|b2|])). zarith.
+ split. rewrite H2;rewrite Hcmp;ring.
+ split. Spec_ww_to_Z r;zarith.
+ rewrite H2.
+ assert (([|a2|] - [|b2|]) * wB + [|a3|] < 0);zarith.
+ apply Zle_lt_trans with (([|a2|] - [|b2|]) * wB + (wB -1));zarith.
+ replace ( ([|a2|] - [|b2|]) * wB + (wB - 1)) with
+ (([|a2|] - [|b2|] + 1) * wB + - 1);[zarith|ring].
+ assert (([|a2|] - [|b2|] + 1) * wB <= 0);zarith.
+ replace 0 with (0*wB);zarith.
+ (* Cas Lt *)
+ assert (Hdiv21 := spec_div21 a2 Hle Hcmp);
+ destruct (w_div21 a1 a2 b1) as (q, r);destruct Hdiv21.
+ rewrite H.
+ assert (Hq := spec_to_Z q).
+ generalize
+ (spec_ww_sub_c (w_WW r a3) (w_mul_c q b2));
+ destruct (ww_sub_c (w_WW r a3) (w_mul_c q b2))
+ as [r1|r1];repeat (rewrite spec_w_WW || rewrite spec_mul_c);
+ unfold interp_carry;intros H1.
+ rewrite H1.
+ split. ring. split.
+ rewrite <- H1;destruct (spec_ww_to_Z w_digits w_to_Z spec_to_Z r1);trivial.
+ apply Zle_lt_trans with ([|r|] * wB + [|a3|]).
+ assert ( 0 <= [|q|] * [|b2|]);zarith.
+ apply beta_lex_inv;zarith.
+ assert ([[r1]] = [|r|] * wB + [|a3|] - [|q|] * [|b2|] + wwB).
+ rewrite <- H1;ring.
+ Spec_ww_to_Z r1; assert (0 <= [|r|]*wB). zarith.
+ assert (0 < [|q|] * [|b2|]). zarith.
+ assert (0 < [|q|]).
+ apply Zmult_lt_0_reg_r_2 with [|b2|];zarith.
+ eapply spec_ww_add_c_cont with (P :=
+ fun (x y:zn2z w) (res:w*zn2z w) =>
+ let (q0, r0) := res in
+ ([|q|] * [|b1|] + [|r|]) * wB + [|a3|] =
+ [|q0|] * ([|b1|] * wB + [|b2|]) + [[r0]] /\
+ 0 <= [[r0]] < [|b1|] * wB + [|b2|]);eauto.
+ intros r2;repeat (rewrite spec_pred || rewrite spec_ww_add;eauto);
+ simpl ww_to_Z;intros H7.
+ assert (0 < [|q|] - 1).
+ assert (1 <= [|q|]). zarith.
+ destruct (Zle_lt_or_eq _ _ H6);zarith.
+ rewrite <- H8 in H2;rewrite H2 in H7.
+ assert (0 < [|b1|]*wB). apply Zmult_lt_0_compat;zarith.
+ Spec_ww_to_Z r2. zarith.
+ rewrite (Zmod_def_small ([|q|] -1));zarith.
+ rewrite (Zmod_def_small ([|q|] -1 -1));zarith.
+ assert ([[r2]] + ([|b1|] * wB + [|b2|]) =
+ wwB * 1 +
+ ([|r|] * wB + [|a3|] - [|q|] * [|b2|] + 2 * ([|b1|] * wB + [|b2|]))).
+ rewrite H7;rewrite H2;ring.
+ assert
+ ([|r|]*wB + [|a3|] - [|q|]*[|b2|] + 2 * ([|b1|]*wB + [|b2|])
+ < [|b1|]*wB + [|b2|]).
+ Spec_ww_to_Z r2;omega.
+ Spec_ww_to_Z (WW b1 b2). simpl in HH5.
+ assert
+ (0 <= [|r|]*wB + [|a3|] - [|q|]*[|b2|] + 2 * ([|b1|]*wB + [|b2|])
+ < wwB). split;try omega.
+ replace (2*([|b1|]*wB+[|b2|])) with ((2*[|b1|])*wB+2*[|b2|]). 2:ring.
+ assert (H12:= wB_div2 Hle). assert (wwB <= 2 * [|b1|] * wB).
+ rewrite wwB_wBwB; rewrite Zpower_2; zarith. omega.
+ rewrite <- (Zmod_unique
+ ([[r2]] + ([|b1|] * wB + [|b2|]))
+ wwB
+ 1
+ ([|r|] * wB + [|a3|] - [|q|] * [|b2|] + 2*([|b1|] * wB + [|b2|]))
+ U1
+ H10 H8).
+ split. ring. zarith.
+ intros r2;repeat (rewrite spec_pred);simpl ww_to_Z;intros H7.
+ rewrite (Zmod_def_small ([|q|] -1));zarith.
+ split.
+ replace [[r2]] with ([[r1]] + ([|b1|] * wB + [|b2|]) -wwB).
+ rewrite H2; ring. rewrite <- H7; ring.
+ Spec_ww_to_Z r2;Spec_ww_to_Z r1. omega.
+ simpl in Hlt.
+ assert ([|a1|] * wB + [|a2|] <= [|b1|] * wB + [|b2|]). zarith.
+ assert (H1 := beta_lex _ _ _ _ _ H HH0 HH3). rewrite spec_w_0;simpl;zarith.
+ Qed.
+
+
+End GenDiv32.
+
+Section GenDiv21.
+ Variable w : Set.
+ Variable w_0 : w.
+
+ Variable w_0W : w -> zn2z w.
+ Variable w_div32 : w -> w -> w -> w -> w -> w * zn2z w.
+
+ Variable ww_1 : zn2z w.
+ Variable ww_compare : zn2z w -> zn2z w -> comparison.
+ Variable ww_sub : zn2z w -> zn2z w -> zn2z w.
+
+
+ Definition ww_div21 a1 a2 b :=
+ match a1 with
+ | W0 =>
+ match ww_compare a2 b with
+ | Gt => (ww_1, ww_sub a2 b)
+ | Eq => (ww_1, W0)
+ | Lt => (W0, a2)
+ end
+ | WW a1h a1l =>
+ match a2 with
+ | W0 =>
+ match b with
+ | W0 => (W0,W0) (* cas absurde *)
+ | WW b1 b2 =>
+ let (q1, r) := w_div32 a1h a1l w_0 b1 b2 in
+ match r with
+ | W0 => (WW q1 w_0, W0)
+ | WW r1 r2 =>
+ let (q2, s) := w_div32 r1 r2 w_0 b1 b2 in
+ (WW q1 q2, s)
+ end
+ end
+ | WW a2h a2l =>
+ match b with
+ | W0 => (W0,W0) (* cas absurde *)
+ | WW b1 b2 =>
+ let (q1, r) := w_div32 a1h a1l a2h b1 b2 in
+ match r with
+ | W0 => (WW q1 w_0, w_0W a2l)
+ | WW r1 r2 =>
+ let (q2, s) := w_div32 r1 r2 a2l b1 b2 in
+ (WW q1 q2, s)
+ end
+ end
+ end
+ end.
+
+ (* Proof *)
+
+ Variable w_digits : positive.
+ Variable w_to_Z : w -> Z.
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+ Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
+ Variable spec_w_div32 : forall a1 a2 a3 b1 b2,
+ wB/2 <= [|b1|] ->
+ [[WW a1 a2]] < [[WW b1 b2]] ->
+ let (q,r) := w_div32 a1 a2 a3 b1 b2 in
+ [|a1|] * wwB + [|a2|] * wB + [|a3|] =
+ [|q|] * ([|b1|] * wB + [|b2|]) + [[r]] /\
+ 0 <= [[r]] < [|b1|] * wB + [|b2|].
+ Variable spec_ww_1 : [[ww_1]] = 1.
+ Variable spec_ww_compare : forall x y,
+ match ww_compare x y with
+ | Eq => [[x]] = [[y]]
+ | Lt => [[x]] < [[y]]
+ | Gt => [[x]] > [[y]]
+ end.
+ Variable spec_ww_sub : forall x y, [[ww_sub x y]] = ([[x]] - [[y]]) mod wwB.
+
+ Theorem wwB_div: wwB = 2 * (wwB / 2).
+ Proof.
+ rewrite wwB_div_2; rewrite Zmult_assoc; rewrite wB_div_2; auto.
+ rewrite <- Zpower_2; apply wwB_wBwB.
+ Qed.
+
+ Ltac Spec_w_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_to_Z x).
+ Ltac Spec_ww_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_ww_to_Z w_digits w_to_Z spec_to_Z x).
+
+ Theorem spec_ww_div21 : forall a1 a2 b,
+ wwB/2 <= [[b]] ->
+ [[a1]] < [[b]] ->
+ let (q,r) := ww_div21 a1 a2 b in
+ [[a1]] *wwB+[[a2]] = [[q]] * [[b]] + [[r]] /\ 0 <= [[r]] < [[b]].
+ Proof.
+ assert (U:= lt_0_wB w_digits).
+ assert (U1:= lt_0_wwB w_digits).
+ intros a1 a2 b H Hlt; unfold ww_div21.
+ Spec_ww_to_Z b; assert (Eq: 0 < [[b]]). Spec_ww_to_Z a1;omega.
+ generalize Hlt H ;clear Hlt H;case a1.
+ intros H1 H2;simpl in H1;Spec_ww_to_Z a2;
+ match goal with |-context [ww_compare ?Y ?Z] =>
+ generalize (spec_ww_compare Y Z); case (ww_compare Y Z)
+ end; simpl;try rewrite spec_ww_1;autorewrite with rm10; intros;zarith.
+ rewrite spec_ww_sub;simpl. rewrite Zmod_def_small;zarith.
+ split. ring.
+ assert (wwB <= 2*[[b]]);zarith.
+ rewrite wwB_div;zarith.
+ intros a1h a1l. Spec_w_to_Z a1h;Spec_w_to_Z a1l. Spec_ww_to_Z a2.
+ destruct a2 as [ |a3 a4];
+ (destruct b as [ |b1 b2];[unfold Zle in Eq;discriminate Eq|idtac]);
+ try (Spec_w_to_Z a3; Spec_w_to_Z a4); Spec_w_to_Z b1; Spec_w_to_Z b2;
+ intros Hlt H; match goal with |-context [w_div32 ?X ?Y ?Z ?T ?U] =>
+ generalize (@spec_w_div32 X Y Z T U); case (w_div32 X Y Z T U);
+ intros q1 r H0
+ end; (assert (Eq1: wB / 2 <= [|b1|]);[
+ apply (@beta_lex (wB / 2) 0 [|b1|] [|b2|] wB); auto with zarith;
+ autorewrite with rm10;repeat rewrite (Zmult_comm wB);
+ rewrite <- wwB_div_2; trivial
+ | generalize (H0 Eq1 Hlt);clear H0;destruct r as [ |r1 r2];simpl;
+ try rewrite spec_w_0; try rewrite spec_w_0W;repeat rewrite Zplus_0_r;
+ intros (H1,H2) ]).
+ split;[rewrite wwB_wBwB; rewrite Zpower_2 | trivial].
+ rewrite Zmult_assoc;rewrite Zmult_plus_distr_l;rewrite <- Zmult_assoc;
+ rewrite <- Zpower_2; rewrite <- wwB_wBwB;rewrite H1;ring.
+ destruct H2 as (H2,H3);match goal with |-context [w_div32 ?X ?Y ?Z ?T ?U] =>
+ generalize (@spec_w_div32 X Y Z T U); case (w_div32 X Y Z T U);
+ intros q r H0;generalize (H0 Eq1 H3);clear H0;intros (H4,H5) end.
+ split;[rewrite wwB_wBwB | trivial].
+ rewrite Zpower_2.
+ rewrite Zmult_assoc;rewrite Zmult_plus_distr_l;rewrite <- Zmult_assoc;
+ rewrite <- Zpower_2.
+ rewrite <- wwB_wBwB;rewrite H1.
+ rewrite spec_w_0 in H4;rewrite Zplus_0_r in H4.
+ repeat rewrite Zmult_plus_distr_l. rewrite <- (Zmult_assoc [|r1|]).
+ rewrite <- Zpower_2; rewrite <- wwB_wBwB;rewrite H4;simpl;ring.
+ split;[rewrite wwB_wBwB | split;zarith].
+ replace (([|a1h|] * wB + [|a1l|]) * wB^2 + ([|a3|] * wB + [|a4|]))
+ with (([|a1h|] * wwB + [|a1l|] * wB + [|a3|])*wB+ [|a4|]).
+ rewrite H1;ring. rewrite wwB_wBwB;ring.
+ change [|a4|] with (0*wB+[|a4|]);apply beta_lex_inv;zarith.
+ assert (1 <= wB/2);zarith.
+ assert (H_:= wB_pos w_digits);apply Zdiv_le_lower_bound;zarith.
+ destruct H2 as (H2,H3);match goal with |-context [w_div32 ?X ?Y ?Z ?T ?U] =>
+ generalize (@spec_w_div32 X Y Z T U); case (w_div32 X Y Z T U);
+ intros q r H0;generalize (H0 Eq1 H3);clear H0;intros (H4,H5) end.
+ split;trivial.
+ replace (([|a1h|] * wB + [|a1l|]) * wwB + ([|a3|] * wB + [|a4|])) with
+ (([|a1h|] * wwB + [|a1l|] * wB + [|a3|])*wB + [|a4|]);
+ [rewrite H1 | rewrite wwB_wBwB;ring].
+ replace (([|q1|]*([|b1|]*wB+[|b2|])+([|r1|]*wB+[|r2|]))*wB+[|a4|]) with
+ (([|q1|]*([|b1|]*wB+[|b2|]))*wB+([|r1|]*wwB+[|r2|]*wB+[|a4|]));
+ [rewrite H4;simpl|rewrite wwB_wBwB];ring.
+ Qed.
+
+End GenDiv21.
+
+Section GenDivGt.
+ Variable w : Set.
+ Variable w_digits : positive.
+ Variable w_0 : w.
+
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_0W : w -> zn2z w.
+ Variable w_compare : w -> w -> comparison.
+ Variable w_eq0 : w -> bool.
+ Variable w_opp_c : w -> carry w.
+ Variable w_opp w_opp_carry : w -> w.
+ Variable w_sub_c : w -> w -> carry w.
+ Variable w_sub w_sub_carry : w -> w -> w.
+
+ Variable w_div_gt : w -> w -> w*w.
+ Variable w_mod_gt : w -> w -> w.
+ Variable w_gcd_gt : w -> w -> w.
+ Variable w_add_mul_div : positive -> w -> w -> w.
+ Variable w_head0 : w -> N.
+ Variable w_div21 : w -> w -> w -> w * w.
+ Variable w_div32 : w -> w -> w -> w -> w -> w * zn2z w.
+
+
+ Variable _ww_digits : positive.
+ Variable ww_1 : zn2z w.
+ Variable ww_add_mul_div : positive -> zn2z w -> zn2z w -> zn2z w.
+
+ Definition ww_div_gt_aux ah al bh bl :=
+ Eval lazy beta iota delta [ww_sub ww_opp] in
+ let nb0 := w_head0 bh in
+ match nb0 with
+ | N0 => (ww_1, ww_sub w_0 w_WW w_opp_c w_opp_carry w_sub_c
+ w_opp w_sub w_sub_carry (WW ah al) (WW bh bl))
+ | Npos p =>
+ let b1 := w_add_mul_div p bh bl in
+ let b2 := w_add_mul_div p bl w_0 in
+ let a1 := w_add_mul_div p w_0 ah in
+ let a2 := w_add_mul_div p ah al in
+ let a3 := w_add_mul_div p al w_0 in
+ let (q,r) := w_div32 a1 a2 a3 b1 b2 in
+ (WW w_0 q, ww_add_mul_div (Pminus _ww_digits p) W0 r)
+ end.
+
+ Definition ww_div_gt a b :=
+ Eval lazy beta iota delta [ww_div_gt_aux gen_divn1
+ gen_divn1_p gen_divn1_p_aux gen_divn1_0 gen_divn1_0_aux
+ gen_split gen_0 gen_WW] in
+ match a, b with
+ | W0, _ => (W0,W0)
+ | _, W0 => (W0,W0)
+ | WW ah al, WW bh bl =>
+ if w_eq0 ah then
+ let (q,r) := w_div_gt al bl in
+ (WW w_0 q, w_0W r)
+ else
+ match w_compare w_0 bh with
+ | Eq =>
+ let(q,r):=
+ gen_divn1 w_digits w_0 w_WW w_head0 w_add_mul_div w_div21 1 a bl in
+ (q, w_0W r)
+ | Lt => ww_div_gt_aux ah al bh bl
+ | Gt => (W0,W0) (* cas absurde *)
+ end
+ end.
+
+ Definition ww_mod_gt_aux ah al bh bl :=
+ Eval lazy beta iota delta [ww_sub ww_opp] in
+ let nb0 := w_head0 bh in
+ match nb0 with
+ | N0 =>
+ ww_sub w_0 w_WW w_opp_c w_opp_carry w_sub_c
+ w_opp w_sub w_sub_carry (WW ah al) (WW bh bl)
+ | Npos p =>
+ let b1 := w_add_mul_div p bh bl in
+ let b2 := w_add_mul_div p bl w_0 in
+ let a1 := w_add_mul_div p w_0 ah in
+ let a2 := w_add_mul_div p ah al in
+ let a3 := w_add_mul_div p al w_0 in
+ let (q,r) := w_div32 a1 a2 a3 b1 b2 in
+ ww_add_mul_div (Pminus _ww_digits p) W0 r
+ end.
+
+ Definition ww_mod_gt a b :=
+ Eval lazy beta iota delta [ww_mod_gt_aux gen_modn1
+ gen_modn1_p gen_modn1_p_aux gen_modn1_0 gen_modn1_0_aux
+ gen_split gen_0 gen_WW snd] in
+ match a, b with
+ | W0, _ => W0
+ | _, W0 => W0
+ | WW ah al, WW bh bl =>
+ if w_eq0 ah then w_0W (w_mod_gt al bl)
+ else
+ match w_compare w_0 bh with
+ | Eq =>
+ w_0W (gen_modn1 w_digits w_0 w_head0 w_add_mul_div w_div21 1 a bl)
+ | Lt => ww_mod_gt_aux ah al bh bl
+ | Gt => W0 (* cas absurde *)
+ end
+ end.
+
+ Definition ww_gcd_gt_body (cont: w->w->w->w->zn2z w) (ah al bh bl: w) :=
+ Eval lazy beta iota delta [ww_mod_gt_aux gen_modn1
+ gen_modn1_p gen_modn1_p_aux gen_modn1_0 gen_modn1_0_aux
+ gen_split gen_0 gen_WW snd] in
+ match w_compare w_0 bh with
+ | Eq =>
+ match w_compare w_0 bl with
+ | Eq => WW ah al (* normalement n'arrive pas si forme normale *)
+ | Lt =>
+ let m := gen_modn1 w_digits w_0 w_head0 w_add_mul_div w_div21 1
+ (WW ah al) bl in
+ WW w_0 (w_gcd_gt bl m)
+ | Gt => W0 (* absurde *)
+ end
+ | Lt =>
+ let m := ww_mod_gt_aux ah al bh bl in
+ match m with
+ | W0 => WW bh bl
+ | WW mh ml =>
+ match w_compare w_0 mh with
+ | Eq =>
+ match w_compare w_0 ml with
+ | Eq => WW bh bl
+ | _ =>
+ let r := gen_modn1 w_digits w_0 w_head0 w_add_mul_div w_div21 1
+ (WW bh bl) ml in
+ WW w_0 (w_gcd_gt ml r)
+ end
+ | Lt =>
+ let r := ww_mod_gt_aux bh bl mh ml in
+ match r with
+ | W0 => m
+ | WW rh rl => cont mh ml rh rl
+ end
+ | Gt => W0 (* absurde *)
+ end
+ end
+ | Gt => W0 (* absurde *)
+ end.
+
+ Fixpoint ww_gcd_gt_aux
+ (p:positive) (cont: w -> w -> w -> w -> zn2z w) (ah al bh bl : w)
+ {struct p} : zn2z w :=
+ ww_gcd_gt_body
+ (fun mh ml rh rl => match p with
+ | xH => cont mh ml rh rl
+ | xO p => ww_gcd_gt_aux p (ww_gcd_gt_aux p cont) mh ml rh rl
+ | xI p => ww_gcd_gt_aux p (ww_gcd_gt_aux p cont) mh ml rh rl
+ end) ah al bh bl.
+
+
+ (* Proof *)
+
+ Variable w_to_Z : w -> Z.
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
+ Variable spec_compare :
+ forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Variable spec_eq0 : forall x, w_eq0 x = true -> [|x|] = 0.
+
+ Variable spec_opp_c : forall x, [-|w_opp_c x|] = -[|x|].
+ Variable spec_opp : forall x, [|w_opp x|] = (-[|x|]) mod wB.
+ Variable spec_opp_carry : forall x, [|w_opp_carry x|] = wB - [|x|] - 1.
+
+ Variable spec_sub_c : forall x y, [-|w_sub_c x y|] = [|x|] - [|y|].
+ Variable spec_sub : forall x y, [|w_sub x y|] = ([|x|] - [|y|]) mod wB.
+ Variable spec_sub_carry :
+ forall x y, [|w_sub_carry x y|] = ([|x|] - [|y|] - 1) mod wB.
+
+ Variable spec_div_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
+ let (q,r) := w_div_gt a b in
+ [|a|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+ Variable spec_mod_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
+ [|w_mod_gt a b|] = [|a|] mod [|b|].
+ Variable spec_gcd_gt : forall a b, [|a|] > [|b|] ->
+ Zis_gcd [|a|] [|b|] [|w_gcd_gt a b|].
+
+ Variable spec_add_mul_div : forall x y p,
+ Zpos p < Zpos w_digits ->
+ [| w_add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos w_digits) - (Zpos p)))) mod wB.
+ Variable spec_head0 : forall x, 0 < [|x|] ->
+ wB/ 2 <= 2 ^ (Z_of_N (w_head0 x)) * [|x|] < wB.
+
+ Variable spec_div21 : forall a1 a2 b,
+ wB/2 <= [|b|] ->
+ [|a1|] < [|b|] ->
+ let (q,r) := w_div21 a1 a2 b in
+ [|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+
+ Variable spec_w_div32 : forall a1 a2 a3 b1 b2,
+ wB/2 <= [|b1|] ->
+ [[WW a1 a2]] < [[WW b1 b2]] ->
+ let (q,r) := w_div32 a1 a2 a3 b1 b2 in
+ [|a1|] * wwB + [|a2|] * wB + [|a3|] =
+ [|q|] * ([|b1|] * wB + [|b2|]) + [[r]] /\
+ 0 <= [[r]] < [|b1|] * wB + [|b2|].
+
+ Variable spec_ww_digits_ : _ww_digits = xO w_digits.
+ Variable spec_ww_1 : [[ww_1]] = 1.
+ Variable spec_ww_add_mul_div : forall x y p,
+ Zpos p < Zpos (xO w_digits) ->
+ [[ ww_add_mul_div p x y ]] =
+ ([[x]] * (2^Zpos p) +
+ [[y]] / (2^(Zpos (xO w_digits) - Zpos p))) mod wwB.
+
+ Ltac Spec_w_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_to_Z x).
+
+ Ltac Spec_ww_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_ww_to_Z w_digits w_to_Z spec_to_Z x).
+
+ Lemma to_Z_div_minus_p : forall x p,
+ 0 < Zpos p < Zpos w_digits ->
+ 0 <= [|x|] / 2 ^ (Zpos w_digits - Zpos p) < 2 ^ Zpos p.
+ Proof.
+ intros x p H;Spec_w_to_Z x.
+ split. apply Zdiv_le_lower_bound;zarith.
+ apply Zdiv_lt_upper_bound;zarith.
+ rewrite <- Zpower_exp;zarith.
+ ring_simplify (Zpos p + (Zpos w_digits - Zpos p)); unfold base in HH;zarith.
+ Qed.
+ Hint Resolve to_Z_div_minus_p : zarith.
+
+ Lemma spec_ww_div_gt_aux : forall ah al bh bl,
+ [[WW ah al]] > [[WW bh bl]] ->
+ 0 < [|bh|] ->
+ let (q,r) := ww_div_gt_aux ah al bh bl in
+ [[WW ah al]] = [[q]] * [[WW bh bl]] + [[r]] /\
+ 0 <= [[r]] < [[WW bh bl]].
+ Proof.
+ intros ah al bh bl Hgt Hpos;unfold ww_div_gt_aux.
+ change
+ (let (q, r) := match w_head0 bh with
+ | N0 => (ww_1, ww_sub w_0 w_WW w_opp_c w_opp_carry w_sub_c
+ w_opp w_sub w_sub_carry (WW ah al) (WW bh bl))
+ | Npos p =>
+ let b1 := w_add_mul_div p bh bl in
+ let b2 := w_add_mul_div p bl w_0 in
+ let a1 := w_add_mul_div p w_0 ah in
+ let a2 := w_add_mul_div p ah al in
+ let a3 := w_add_mul_div p al w_0 in
+ let (q,r) := w_div32 a1 a2 a3 b1 b2 in
+ (WW w_0 q, ww_add_mul_div (Pminus _ww_digits p) W0 r)
+ end in [[WW ah al]]=[[q]]*[[WW bh bl]]+[[r]] /\ 0 <=[[r]]< [[WW bh bl]]).
+ assert (Hh := spec_head0 Hpos);destruct (w_head0 bh).
+ simpl Zpower in Hh;rewrite Zmult_1_l in Hh;destruct Hh.
+ assert (wwB <= 2*[[WW bh bl]]).
+ apply Zle_trans with (2*[|bh|]*wB).
+ rewrite wwB_wBwB; rewrite Zpower_2; apply Zmult_le_compat_r; zarith.
+ rewrite <- wB_div_2; apply Zmult_le_compat_l; zarith.
+ simpl ww_to_Z;rewrite Zmult_plus_distr_r;rewrite Zmult_assoc.
+ Spec_w_to_Z bl;zarith.
+ Spec_ww_to_Z (WW ah al).
+ rewrite spec_ww_sub;eauto.
+ simpl;rewrite spec_ww_1;rewrite Zmult_1_l;simpl.
+ simpl ww_to_Z in Hgt, H1, HH;rewrite Zmod_def_small;split;zarith.
+ unfold Z_of_N in Hh.
+ assert (Zpos p < Zpos w_digits).
+ destruct (Z_lt_ge_dec (Zpos p) (Zpos w_digits));trivial.
+ elimtype False.
+ assert (2 ^ Zpos p * [|bh|] >= wB);auto with zarith.
+ apply Zle_ge; replace wB with (wB * 1);try ring.
+ Spec_w_to_Z bh;apply Zmult_le_compat;zarith.
+ unfold base;apply Zpower_le_monotone;zarith.
+ assert (HHHH : 0 < Zpos p < Zpos w_digits).
+ split;trivial. unfold Zlt;reflexivity.
+ generalize (spec_add_mul_div w_0 ah H)
+ (spec_add_mul_div ah al H)
+ (spec_add_mul_div al w_0 H)
+ (spec_add_mul_div bh bl H)
+ (spec_add_mul_div bl w_0 H);
+ rewrite spec_w_0; repeat rewrite Zmult_0_l;repeat rewrite Zplus_0_l;
+ rewrite Zdiv_0;repeat rewrite Zplus_0_r.
+ Spec_w_to_Z ah;Spec_w_to_Z bh. 2:apply Zpower_lt_0;zarith.
+ unfold base;repeat rewrite Zmod_shift_r;zarith.
+ assert (H3:=to_Z_div_minus_p ah HHHH);assert(H4:=to_Z_div_minus_p al HHHH);
+ assert (H5:=to_Z_div_minus_p bl HHHH).
+ rewrite Zmult_comm in Hh.
+ assert (2^Zpos p < wB). unfold base;apply Zpower_lt_monotone;zarith.
+ unfold base in H0;rewrite Zmod_def_small;zarith.
+ fold wB; rewrite (Zmod_def_small ([|bh|] * 2 ^ Zpos p));zarith.
+ intros U1 U2 U3 V1 V2.
+ generalize (@spec_w_div32 (w_add_mul_div p w_0 ah)
+ (w_add_mul_div p ah al)
+ (w_add_mul_div p al w_0)
+ (w_add_mul_div p bh bl)
+ (w_add_mul_div p bl w_0)).
+ destruct (w_div32 (w_add_mul_div p w_0 ah)
+ (w_add_mul_div p ah al)
+ (w_add_mul_div p al w_0)
+ (w_add_mul_div p bh bl)
+ (w_add_mul_div p bl w_0)) as (q,r).
+ rewrite V1;rewrite V2. rewrite Zmult_plus_distr_l.
+ rewrite <- (Zplus_assoc ([|bh|] * 2 ^ Zpos p * wB)).
+ unfold base;rewrite <- shift_unshift_mod;zarith. fold wB.
+ replace ([|bh|] * 2 ^ Zpos p * wB + [|bl|] * 2 ^ Zpos p) with
+ ([[WW bh bl]] * 2^Zpos p). 2:simpl;ring.
+ fold wwB. rewrite wwB_wBwB. rewrite Zpower_2. rewrite U1;rewrite U2;rewrite U3.
+ rewrite Zmult_assoc. rewrite Zmult_plus_distr_l.
+ rewrite (Zplus_assoc ([|ah|] / 2^(Zpos(w_digits) - Zpos p)*wB * wB)).
+ rewrite <- Zmult_plus_distr_l. rewrite <- Zplus_assoc.
+ unfold base;repeat rewrite <- shift_unshift_mod;zarith. fold wB.
+ replace ([|ah|] * 2 ^ Zpos p * wB + [|al|] * 2 ^ Zpos p) with
+ ([[WW ah al]] * 2^Zpos p). 2:simpl;ring.
+ intros Hd;destruct Hd;zarith.
+ simpl. apply beta_lex_inv;zarith. rewrite U1;rewrite V1.
+ assert ([|ah|] / 2 ^ (Zpos (w_digits) - Zpos p) < wB/2);zarith.
+ apply Zdiv_lt_upper_bound;zarith.
+ unfold base.
+ replace (2^Zpos (w_digits)) with (2^(Zpos (w_digits) - 1)*2).
+ rewrite Z_div_mult;zarith. rewrite <- Zpower_exp;zarith.
+ apply Zlt_le_trans with wB;zarith.
+ unfold base;apply Zpower_le_monotone;zarith.
+ pattern 2 at 2;replace 2 with (2^1);trivial.
+ rewrite <- Zpower_exp;zarith. ring_simplify (Zpos (w_digits) - 1 + 1);trivial.
+ change [[WW w_0 q]] with ([|w_0|]*wB+[|q|]);rewrite spec_w_0;rewrite
+ Zmult_0_l;rewrite Zplus_0_l;rewrite spec_ww_digits_.
+ replace [[ww_add_mul_div (xO (w_digits) - p) W0 r]] with ([[r]]/2^Zpos p).
+ assert (0 < 2^Zpos p). apply Zpower_lt_0;zarith.
+ split.
+ rewrite <- (Z_div_mult [[WW ah al]] (2^Zpos p));zarith.
+ rewrite H1;rewrite Zmult_assoc;apply Z_div_plus_l;trivial.
+ split;[apply Zdiv_le_lower_bound| apply Zdiv_lt_upper_bound];zarith.
+ rewrite spec_ww_add_mul_div;rewrite Zpos_minus.
+ change (Zpos (xO (w_digits))) with (2*Zpos (w_digits));zarith.
+ simpl ww_to_Z;rewrite Zmult_0_l;rewrite Zplus_0_l.
+ ring_simplify (2*Zpos (w_digits)-(2*Zpos (w_digits) - Zpos p));trivial.
+ rewrite Zmod_def_small;zarith.
+ split;[apply Zdiv_le_lower_bound| apply Zdiv_lt_upper_bound];zarith.
+ Spec_ww_to_Z r.
+ apply Zlt_le_trans with wwB;zarith.
+ rewrite <- (Zmult_1_r wwB);apply Zmult_le_compat;zarith.
+ rewrite Zpos_xO;zarith. rewrite Zpos_xO;zarith. rewrite Zpos_xO;zarith.
+ Qed.
+
+ Lemma spec_ww_div_gt : forall a b, [[a]] > [[b]] -> 0 < [[b]] ->
+ let (q,r) := ww_div_gt a b in
+ [[a]] = [[q]] * [[b]] + [[r]] /\
+ 0 <= [[r]] < [[b]].
+ Proof.
+ intros a b Hgt Hpos;unfold ww_div_gt.
+ change (let (q,r) := match a, b with
+ | W0, _ => (W0,W0)
+ | _, W0 => (W0,W0)
+ | WW ah al, WW bh bl =>
+ if w_eq0 ah then let (q,r) := w_div_gt al bl in (WW w_0 q, w_0W r)
+ else
+ match w_compare w_0 bh with
+ | Eq =>
+ let(q,r):=
+ gen_divn1 w_digits w_0 w_WW w_head0 w_add_mul_div w_div21 1 a bl in
+ (q, w_0W r)
+ | Lt => ww_div_gt_aux ah al bh bl
+ | Gt => (W0,W0) (* cas absurde *)
+ end
+ end in [[a]] = [[q]] * [[b]] + [[r]] /\ 0 <= [[r]] < [[b]]).
+ destruct a as [ |ah al]. simpl in Hgt;omega.
+ destruct b as [ |bh bl]. simpl in Hpos;omega.
+ Spec_w_to_Z ah; Spec_w_to_Z al; Spec_w_to_Z bh; Spec_w_to_Z bl.
+ assert (H:=@spec_eq0 ah);destruct (w_eq0 ah).
+ simpl ww_to_Z;rewrite H;trivial. simpl in Hgt;rewrite H in Hgt;trivial.
+ assert ([|bh|] <= 0).
+ apply beta_lex with (d:=[|al|])(b:=[|bl|]) (beta := wB);zarith.
+ assert ([|bh|] = 0);zarith. rewrite H1 in Hgt;rewrite H1;simpl in Hgt.
+ simpl. simpl in Hpos;rewrite H1 in Hpos;simpl in Hpos.
+ assert (H2:=spec_div_gt Hgt Hpos);destruct (w_div_gt al bl).
+ repeat rewrite spec_w_0W;simpl;rewrite spec_w_0;simpl;trivial.
+ clear H.
+ assert (Hcmp := spec_compare w_0 bh); destruct (w_compare w_0 bh).
+ rewrite spec_w_0 in Hcmp. change [[WW bh bl]] with ([|bh|]*wB+[|bl|]).
+ rewrite <- Hcmp;rewrite Zmult_0_l;rewrite Zplus_0_l.
+ simpl in Hpos;rewrite <- Hcmp in Hpos;simpl in Hpos.
+ assert (H2:= @spec_gen_divn1 w w_digits w_0 w_WW w_head0 w_add_mul_div
+ w_div21 w_to_Z spec_to_Z spec_w_0 spec_w_WW spec_head0
+ spec_add_mul_div spec_div21 1 (WW ah al) bl Hpos).
+ unfold gen_to_Z,gen_wB,gen_digits in H2.
+ destruct (gen_divn1 w_digits w_0 w_WW w_head0 w_add_mul_div w_div21 1
+ (WW ah al) bl).
+ rewrite spec_w_0W;unfold ww_to_Z;trivial.
+ apply spec_ww_div_gt_aux;trivial. rewrite spec_w_0 in Hcmp;trivial.
+ rewrite spec_w_0 in Hcmp;elimtype False;omega.
+ Qed.
+
+ Lemma spec_ww_mod_gt_aux_eq : forall ah al bh bl,
+ ww_mod_gt_aux ah al bh bl = snd (ww_div_gt_aux ah al bh bl).
+ Proof.
+ intros ah al bh bl. unfold ww_mod_gt_aux, ww_div_gt_aux.
+ destruct (w_head0 bh). trivial.
+ destruct (w_div32 (w_add_mul_div p w_0 ah) (w_add_mul_div p ah al)
+ (w_add_mul_div p al w_0) (w_add_mul_div p bh bl)
+ (w_add_mul_div p bl w_0));trivial.
+ Qed.
+
+ Lemma spec_ww_mod_gt_aux : forall ah al bh bl,
+ [[WW ah al]] > [[WW bh bl]] ->
+ 0 < [|bh|] ->
+ [[ww_mod_gt_aux ah al bh bl]] = [[WW ah al]] mod [[WW bh bl]].
+ Proof.
+ intros. rewrite spec_ww_mod_gt_aux_eq;trivial.
+ assert (H3 := spec_ww_div_gt_aux ah al bl H H0).
+ destruct (ww_div_gt_aux ah al bh bl) as (q,r);simpl. simpl in H,H3.
+ destruct H3;apply Zmod_unique with [[q]];zarith.
+ rewrite H1;ring.
+ Qed.
+
+ Lemma spec_w_mod_gt_eq : forall a b, [|a|] > [|b|] -> 0 <[|b|] ->
+ [|w_mod_gt a b|] = [|snd (w_div_gt a b)|].
+ Proof.
+ intros a b Hgt Hpos.
+ rewrite spec_mod_gt;trivial.
+ assert (H:=spec_div_gt Hgt Hpos).
+ destruct (w_div_gt a b) as (q,r);simpl.
+ rewrite Zmult_comm in H;destruct H.
+ symmetry;apply Zmod_unique with [|q|];trivial.
+ Qed.
+
+ Lemma spec_ww_mod_gt_eq : forall a b, [[a]] > [[b]] -> 0 < [[b]] ->
+ [[ww_mod_gt a b]] = [[snd (ww_div_gt a b)]].
+ Proof.
+ intros a b Hgt Hpos.
+ change (ww_mod_gt a b) with
+ (match a, b with
+ | W0, _ => W0
+ | _, W0 => W0
+ | WW ah al, WW bh bl =>
+ if w_eq0 ah then w_0W (w_mod_gt al bl)
+ else
+ match w_compare w_0 bh with
+ | Eq =>
+ w_0W (gen_modn1 w_digits w_0 w_head0 w_add_mul_div w_div21 1 a bl)
+ | Lt => ww_mod_gt_aux ah al bh bl
+ | Gt => W0 (* cas absurde *)
+ end
+ end).
+ change (ww_div_gt a b) with
+ (match a, b with
+ | W0, _ => (W0,W0)
+ | _, W0 => (W0,W0)
+ | WW ah al, WW bh bl =>
+ if w_eq0 ah then let (q,r) := w_div_gt al bl in (WW w_0 q, w_0W r)
+ else
+ match w_compare w_0 bh with
+ | Eq =>
+ let(q,r):=
+ gen_divn1 w_digits w_0 w_WW w_head0 w_add_mul_div w_div21 1 a bl in
+ (q, w_0W r)
+ | Lt => ww_div_gt_aux ah al bh bl
+ | Gt => (W0,W0) (* cas absurde *)
+ end
+ end).
+ destruct a as [ |ah al];trivial.
+ destruct b as [ |bh bl];trivial.
+ Spec_w_to_Z ah; Spec_w_to_Z al; Spec_w_to_Z bh; Spec_w_to_Z bl.
+ assert (H:=@spec_eq0 ah);destruct (w_eq0 ah).
+ simpl in Hgt;rewrite H in Hgt;trivial.
+ assert ([|bh|] <= 0).
+ apply beta_lex with (d:=[|al|])(b:=[|bl|]) (beta := wB);zarith.
+ assert ([|bh|] = 0);zarith. rewrite H1 in Hgt;simpl in Hgt.
+ simpl in Hpos;rewrite H1 in Hpos;simpl in Hpos.
+ rewrite spec_w_0W;rewrite spec_w_mod_gt_eq;trivial.
+ destruct (w_div_gt al bl);simpl;rewrite spec_w_0W;trivial.
+ clear H.
+ assert (H2 := spec_compare w_0 bh);destruct (w_compare w_0 bh).
+ rewrite (@spec_gen_modn1_aux w w_digits w_0 w_WW w_head0 w_add_mul_div
+ w_div21 1 (WW ah al) bl).
+ destruct (gen_divn1 w_digits w_0 w_WW w_head0 w_add_mul_div w_div21 1
+ (WW ah al) bl);simpl;trivial.
+ rewrite spec_ww_mod_gt_aux_eq;trivial;symmetry;trivial.
+ trivial.
+ Qed.
+
+ Lemma spec_ww_mod_gt : forall a b, [[a]] > [[b]] -> 0 < [[b]] ->
+ [[ww_mod_gt a b]] = [[a]] mod [[b]].
+ Proof.
+ intros a b Hgt Hpos.
+ assert (H:= spec_ww_div_gt a b Hgt Hpos).
+ rewrite (spec_ww_mod_gt_eq a b Hgt Hpos).
+ destruct (ww_div_gt a b)as(q,r);destruct H.
+ apply Zmod_unique with[[q]];simpl;trivial.
+ rewrite Zmult_comm;trivial.
+ Qed.
+
+ Lemma Zis_gcd_mod : forall a b d,
+ 0 < b -> Zis_gcd b (a mod b) d -> Zis_gcd a b d.
+ Proof.
+ intros a b d H H1; apply Zis_gcd_for_euclid with (a/b).
+ pattern a at 1;rewrite (Z_div_mod_eq a b).
+ ring_simplify (b * (a / b) + a mod b - a / b * b);trivial. zarith.
+ Qed.
+
+ Lemma spec_ww_gcd_gt_aux_body :
+ forall ah al bh bl n cont,
+ [[WW bh bl]] <= 2^n ->
+ [[WW ah al]] > [[WW bh bl]] ->
+ (forall xh xl yh yl,
+ [[WW xh xl]] > [[WW yh yl]] -> [[WW yh yl]] <= 2^(n-1) ->
+ Zis_gcd [[WW xh xl]] [[WW yh yl]] [[cont xh xl yh yl]]) ->
+ Zis_gcd [[WW ah al]] [[WW bh bl]] [[ww_gcd_gt_body cont ah al bh bl]].
+ Proof.
+ intros ah al bh bl n cont Hlog Hgt Hcont.
+ change (ww_gcd_gt_body cont ah al bh bl) with (match w_compare w_0 bh with
+ | Eq =>
+ match w_compare w_0 bl with
+ | Eq => WW ah al (* normalement n'arrive pas si forme normale *)
+ | Lt =>
+ let m := gen_modn1 w_digits w_0 w_head0 w_add_mul_div w_div21 1
+ (WW ah al) bl in
+ WW w_0 (w_gcd_gt bl m)
+ | Gt => W0 (* absurde *)
+ end
+ | Lt =>
+ let m := ww_mod_gt_aux ah al bh bl in
+ match m with
+ | W0 => WW bh bl
+ | WW mh ml =>
+ match w_compare w_0 mh with
+ | Eq =>
+ match w_compare w_0 ml with
+ | Eq => WW bh bl
+ | _ =>
+ let r := gen_modn1 w_digits w_0 w_head0 w_add_mul_div w_div21 1
+ (WW bh bl) ml in
+ WW w_0 (w_gcd_gt ml r)
+ end
+ | Lt =>
+ let r := ww_mod_gt_aux bh bl mh ml in
+ match r with
+ | W0 => m
+ | WW rh rl => cont mh ml rh rl
+ end
+ | Gt => W0 (* absurde *)
+ end
+ end
+ | Gt => W0 (* absurde *)
+ end).
+ assert (Hbh := spec_compare w_0 bh);destruct (w_compare w_0 bh).
+ simpl ww_to_Z in *. rewrite spec_w_0 in Hbh;rewrite <- Hbh;
+ rewrite Zmult_0_l;rewrite Zplus_0_l.
+ assert (Hbl := spec_compare w_0 bl); destruct (w_compare w_0 bl).
+ rewrite spec_w_0 in Hbl;rewrite <- Hbl;apply Zis_gcd_0.
+ simpl;rewrite spec_w_0;rewrite Zmult_0_l;rewrite Zplus_0_l.
+ rewrite spec_w_0 in Hbl.
+ apply Zis_gcd_mod;zarith.
+ change ([|ah|] * wB + [|al|]) with (gen_to_Z w_digits w_to_Z 1 (WW ah al)).
+ rewrite <- (@spec_gen_modn1 w w_digits w_0 w_WW w_head0 w_add_mul_div
+ w_div21 w_to_Z spec_to_Z spec_w_0 spec_w_WW spec_head0 spec_add_mul_div
+ spec_div21 1 (WW ah al) bl Hbl).
+ apply spec_gcd_gt. rewrite spec_gen_modn1 with (w_WW := w_WW);trivial.
+ apply Zlt_gt;match goal with | |- ?x mod ?y < ?y =>
+ destruct (Z_mod_lt x y);zarith end.
+ rewrite spec_w_0 in Hbl;Spec_w_to_Z bl;elimtype False;omega.
+ rewrite spec_w_0 in Hbh;assert (H:= spec_ww_mod_gt_aux _ _ _ Hgt Hbh).
+ assert (H2 : 0 < [[WW bh bl]]).
+ simpl;Spec_w_to_Z bl. apply Zlt_le_trans with ([|bh|]*wB);zarith.
+ apply Zmult_lt_0_compat;zarith.
+ apply Zis_gcd_mod;trivial. rewrite <- H.
+ simpl in *;destruct (ww_mod_gt_aux ah al bh bl) as [ |mh ml].
+ simpl;apply Zis_gcd_0;zarith.
+ assert (Hmh := spec_compare w_0 mh);destruct (w_compare w_0 mh).
+ simpl;rewrite spec_w_0 in Hmh; rewrite <- Hmh;simpl.
+ assert (Hml := spec_compare w_0 ml);destruct (w_compare w_0 ml).
+ rewrite <- Hml;rewrite spec_w_0;simpl;apply Zis_gcd_0.
+ simpl;rewrite spec_w_0;simpl.
+ rewrite spec_w_0 in Hml. apply Zis_gcd_mod;zarith.
+ change ([|bh|] * wB + [|bl|]) with (gen_to_Z w_digits w_to_Z 1 (WW bh bl)).
+ rewrite <- (@spec_gen_modn1 w w_digits w_0 w_WW w_head0 w_add_mul_div
+ w_div21 w_to_Z spec_to_Z spec_w_0 spec_w_WW spec_head0 spec_add_mul_div
+ spec_div21 1 (WW bh bl) ml Hml).
+ apply spec_gcd_gt. rewrite spec_gen_modn1 with (w_WW := w_WW);trivial.
+ apply Zlt_gt;match goal with | |- ?x mod ?y < ?y =>
+ destruct (Z_mod_lt x y);zarith end.
+ rewrite spec_w_0 in Hml;Spec_w_to_Z ml;elimtype False;omega.
+ rewrite spec_w_0 in Hmh. assert ([[WW bh bl]] > [[WW mh ml]]).
+ rewrite H;simpl; apply Zlt_gt;match goal with | |- ?x mod ?y < ?y =>
+ destruct (Z_mod_lt x y);zarith end.
+ assert (H1:= spec_ww_mod_gt_aux _ _ _ H0 Hmh).
+ assert (H3 : 0 < [[WW mh ml]]).
+ simpl;Spec_w_to_Z ml. apply Zlt_le_trans with ([|mh|]*wB);zarith.
+ apply Zmult_lt_0_compat;zarith.
+ apply Zis_gcd_mod;zarith. simpl in *;rewrite <- H1.
+ destruct (ww_mod_gt_aux bh bl mh ml) as [ |rh rl]. simpl; apply Zis_gcd_0.
+ simpl;apply Hcont. simpl in H1;rewrite H1.
+ apply Zlt_gt;match goal with | |- ?x mod ?y < ?y =>
+ destruct (Z_mod_lt x y);zarith end.
+ apply Zle_trans with (2^n/2).
+ apply Zdiv_le_lower_bound;zarith.
+ apply Zle_trans with ([|bh|] * wB + [|bl|]);zarith.
+ assert (H3' := Z_div_mod_eq [[WW bh bl]] [[WW mh ml]] (Zlt_gt _ _ H3)).
+ assert (H4' : 0 <= [[WW bh bl]]/[[WW mh ml]]).
+ apply Zge_le;apply Z_div_ge0;zarith. simpl in *;rewrite H1.
+ pattern ([|bh|] * wB + [|bl|]) at 2;rewrite H3'.
+ destruct (Zle_lt_or_eq _ _ H4').
+ assert (H6' : [[WW bh bl]] mod [[WW mh ml]] =
+ [[WW bh bl]] - [[WW mh ml]] * ([[WW bh bl]]/[[WW mh ml]])).
+ simpl;pattern ([|bh|] * wB + [|bl|]) at 2;rewrite H3';ring. simpl in H6'.
+ assert ([[WW mh ml]] <= [[WW mh ml]] * ([[WW bh bl]]/[[WW mh ml]])).
+ simpl;pattern ([|mh|]*wB+[|ml|]) at 1;rewrite <- Zmult_1_r;zarith.
+ simpl in *;assert (H8 := Z_mod_lt [[WW bh bl]] [[WW mh ml]]);simpl in H8;
+ zarith.
+ assert (H8 := Z_mod_lt [[WW bh bl]] [[WW mh ml]]);simpl in *;zarith.
+ rewrite <- H4 in H3';rewrite Zmult_0_r in H3';simpl in H3';zarith.
+ pattern n at 1;replace n with (n-1+1);try ring.
+ rewrite Zpower_exp;zarith. change (2^1) with 2.
+ rewrite Z_div_mult;zarith.
+ assert (2^1 <= 2^n). change (2^1) with 2;zarith.
+ assert (H7 := @Zpower_le_monotone_inv 2 1 n);zarith.
+ rewrite spec_w_0 in Hmh;Spec_w_to_Z mh;elimtype False;zarith.
+ rewrite spec_w_0 in Hbh;Spec_w_to_Z bh;elimtype False;zarith.
+ Qed.
+
+ Lemma spec_ww_gcd_gt_aux :
+ forall p cont n,
+ (forall xh xl yh yl,
+ [[WW xh xl]] > [[WW yh yl]] ->
+ [[WW yh yl]] <= 2^n ->
+ Zis_gcd [[WW xh xl]] [[WW yh yl]] [[cont xh xl yh yl]]) ->
+ forall ah al bh bl , [[WW ah al]] > [[WW bh bl]] ->
+ [[WW bh bl]] <= 2^(Zpos p + n) ->
+ Zis_gcd [[WW ah al]] [[WW bh bl]]
+ [[ww_gcd_gt_aux p cont ah al bh bl]].
+ Proof.
+ induction p;intros cont n Hcont ah al bh bl Hgt Hs;simpl ww_gcd_gt_aux.
+ assert (0 < Zpos p). unfold Zlt;reflexivity.
+ apply spec_ww_gcd_gt_aux_body with (n := Zpos (xI p) + n);
+ trivial;rewrite Zpos_xI.
+ intros. apply IHp with (n := Zpos p + n);zarith.
+ intros. apply IHp with (n := n );zarith.
+ apply Zle_trans with (2 ^ (2* Zpos p + 1+ n -1));zarith.
+ apply Zpower_le_monotone2;zarith.
+ assert (0 < Zpos p). unfold Zlt;reflexivity.
+ apply spec_ww_gcd_gt_aux_body with (n := Zpos (xO p) + n );trivial.
+ rewrite (Zpos_xO p).
+ intros. apply IHp with (n := Zpos p + n - 1);zarith.
+ intros. apply IHp with (n := n -1 );zarith.
+ intros;apply Hcont;zarith.
+ apply Zle_trans with (2^(n-1));zarith.
+ apply Zpower_le_monotone2;zarith.
+ apply Zle_trans with (2 ^ (Zpos p + n -1));zarith.
+ apply Zpower_le_monotone2;zarith.
+ apply Zle_trans with (2 ^ (2*Zpos p + n -1));zarith.
+ apply Zpower_le_monotone2;zarith.
+ apply spec_ww_gcd_gt_aux_body with (n := n+1);trivial.
+ rewrite Zplus_comm;trivial.
+ ring_simplify (n + 1 - 1);trivial.
+ Qed.
+
+End GenDivGt.
+
+Section GenDiv.
+
+ Variable w : Set.
+ Variable w_digits : positive.
+ Variable ww_1 : zn2z w.
+ Variable ww_compare : zn2z w -> zn2z w -> comparison.
+
+ Variable ww_div_gt : zn2z w -> zn2z w -> zn2z w * zn2z w.
+ Variable ww_mod_gt : zn2z w -> zn2z w -> zn2z w.
+
+ Definition ww_div a b :=
+ match ww_compare a b with
+ | Gt => ww_div_gt a b
+ | Eq => (ww_1, W0)
+ | Lt => (W0, a)
+ end.
+
+ Definition ww_mod a b :=
+ match ww_compare a b with
+ | Gt => ww_mod_gt a b
+ | Eq => W0
+ | Lt => a
+ end.
+
+ Variable w_to_Z : w -> Z.
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+ Variable spec_ww_1 : [[ww_1]] = 1.
+ Variable spec_ww_compare : forall x y,
+ match ww_compare x y with
+ | Eq => [[x]] = [[y]]
+ | Lt => [[x]] < [[y]]
+ | Gt => [[x]] > [[y]]
+ end.
+ Variable spec_ww_div_gt : forall a b, [[a]] > [[b]] -> 0 < [[b]] ->
+ let (q,r) := ww_div_gt a b in
+ [[a]] = [[q]] * [[b]] + [[r]] /\
+ 0 <= [[r]] < [[b]].
+ Variable spec_ww_mod_gt : forall a b, [[a]] > [[b]] -> 0 < [[b]] ->
+ [[ww_mod_gt a b]] = [[a]] mod [[b]].
+
+ Ltac Spec_w_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_to_Z x).
+
+ Ltac Spec_ww_to_Z x :=
+ let H:= fresh "HH" in
+ assert (H:= spec_ww_to_Z w_digits w_to_Z spec_to_Z x).
+
+ Lemma spec_ww_div : forall a b, 0 < [[b]] ->
+ let (q,r) := ww_div a b in
+ [[a]] = [[q]] * [[b]] + [[r]] /\
+ 0 <= [[r]] < [[b]].
+ Proof.
+ intros a b Hpos;unfold ww_div.
+ assert (H:=spec_ww_compare a b);destruct (ww_compare a b).
+ simpl;rewrite spec_ww_1;split;zarith.
+ simpl;split;[ring|Spec_ww_to_Z a;zarith].
+ apply spec_ww_div_gt;trivial.
+ Qed.
+
+ Lemma spec_ww_mod : forall a b, 0 < [[b]] ->
+ [[ww_mod a b]] = [[a]] mod [[b]].
+ Proof.
+ intros a b Hpos;unfold ww_mod.
+ assert (H := spec_ww_compare a b);destruct (ww_compare a b).
+ simpl;apply Zmod_unique with 1;try rewrite H;zarith.
+ Spec_ww_to_Z a;symmetry;apply Zmod_def_small;zarith.
+ apply spec_ww_mod_gt;trivial.
+ Qed.
+
+
+ Variable w_0 : w.
+ Variable w_1 : w.
+ Variable w_compare : w -> w -> comparison.
+ Variable w_eq0 : w -> bool.
+ Variable w_gcd_gt : w -> w -> w.
+ Variable _ww_digits : positive.
+ Variable spec_ww_digits_ : _ww_digits = xO w_digits.
+ Variable ww_gcd_gt_fix :
+ positive -> (w -> w -> w -> w -> zn2z w) ->
+ w -> w -> w -> w -> zn2z w.
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_1 : [|w_1|] = 1.
+ Variable spec_compare :
+ forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Variable spec_eq0 : forall x, w_eq0 x = true -> [|x|] = 0.
+ Variable spec_gcd_gt : forall a b, [|a|] > [|b|] ->
+ Zis_gcd [|a|] [|b|] [|w_gcd_gt a b|].
+ Variable spec_gcd_gt_fix :
+ forall p cont n,
+ (forall xh xl yh yl,
+ [[WW xh xl]] > [[WW yh yl]] ->
+ [[WW yh yl]] <= 2^n ->
+ Zis_gcd [[WW xh xl]] [[WW yh yl]] [[cont xh xl yh yl]]) ->
+ forall ah al bh bl , [[WW ah al]] > [[WW bh bl]] ->
+ [[WW bh bl]] <= 2^(Zpos p + n) ->
+ Zis_gcd [[WW ah al]] [[WW bh bl]]
+ [[ww_gcd_gt_fix p cont ah al bh bl]].
+
+ Definition gcd_cont (xh xl yh yl:w) :=
+ match w_compare w_1 yl with
+ | Eq => ww_1
+ | _ => WW xh xl
+ end.
+
+ Lemma spec_gcd_cont : forall xh xl yh yl,
+ [[WW xh xl]] > [[WW yh yl]] ->
+ [[WW yh yl]] <= 1 ->
+ Zis_gcd [[WW xh xl]] [[WW yh yl]] [[gcd_cont xh xl yh yl]].
+ Proof.
+ intros xh xl yh yl Hgt' Hle. simpl in Hle.
+ assert ([|yh|] = 0).
+ change 1 with (0*wB+1) in Hle.
+ assert (0 <= 1 < wB). split;zarith. apply wB_pos.
+ assert (H1:= beta_lex _ _ _ _ _ Hle (spec_to_Z yl) H).
+ Spec_w_to_Z yh;zarith.
+ unfold gcd_cont;assert (Hcmpy:=spec_compare w_1 yl);
+ rewrite spec_w_1 in Hcmpy.
+ simpl;rewrite H;simpl;destruct (w_compare w_1 yl).
+ rewrite spec_ww_1;rewrite <- Hcmpy;apply Zis_gcd_mod;zarith.
+ rewrite <- (Zmod_unique ([|xh|]*wB+[|xl|]) 1 ([|xh|]*wB+[|xl|]) 0);zarith.
+ rewrite H in Hle; elimtype False;zarith.
+ assert ([|yl|] = 0). Spec_w_to_Z yl;zarith.
+ rewrite H0;simpl;apply Zis_gcd_0;trivial.
+ Qed.
+
+
+ Variable cont : w -> w -> w -> w -> zn2z w.
+ Variable spec_cont : forall xh xl yh yl,
+ [[WW xh xl]] > [[WW yh yl]] ->
+ [[WW yh yl]] <= 1 ->
+ Zis_gcd [[WW xh xl]] [[WW yh yl]] [[cont xh xl yh yl]].
+
+ Definition ww_gcd_gt a b :=
+ match a, b with
+ | W0, _ => b
+ | _, W0 => a
+ | WW ah al, WW bh bl =>
+ if w_eq0 ah then (WW w_0 (w_gcd_gt al bl))
+ else ww_gcd_gt_fix _ww_digits cont ah al bh bl
+ end.
+
+ Definition ww_gcd a b :=
+ Eval lazy beta delta [ww_gcd_gt] in
+ match ww_compare a b with
+ | Gt => ww_gcd_gt a b
+ | Eq => a
+ | Lt => ww_gcd_gt b a
+ end.
+
+ Lemma spec_ww_gcd_gt : forall a b, [[a]] > [[b]] ->
+ Zis_gcd [[a]] [[b]] [[ww_gcd_gt a b]].
+ Proof.
+ intros a b Hgt;unfold ww_gcd_gt.
+ destruct a as [ |ah al]. simpl;apply Zis_gcd_sym;apply Zis_gcd_0.
+ destruct b as [ |bh bl]. simpl;apply Zis_gcd_0.
+ simpl in Hgt. generalize (@spec_eq0 ah);destruct (w_eq0 ah);intros.
+ simpl;rewrite H in Hgt;trivial;rewrite H;trivial;rewrite spec_w_0;simpl.
+ assert ([|bh|] <= 0).
+ apply beta_lex with (d:=[|al|])(b:=[|bl|]) (beta := wB);zarith.
+ Spec_w_to_Z bh;assert ([|bh|] = 0);zarith. rewrite H1 in Hgt;simpl in Hgt.
+ rewrite H1;simpl;auto. clear H.
+ apply spec_gcd_gt_fix with (n:= 0);trivial.
+ rewrite Zplus_0_r;rewrite spec_ww_digits_.
+ change (2 ^ Zpos (xO w_digits)) with wwB. Spec_ww_to_Z (WW bh bl);zarith.
+ Qed.
+
+ Lemma spec_ww_gcd : forall a b, Zis_gcd [[a]] [[b]] [[ww_gcd a b]].
+ Proof.
+ intros a b.
+ change (ww_gcd a b) with
+ (match ww_compare a b with
+ | Gt => ww_gcd_gt a b
+ | Eq => a
+ | Lt => ww_gcd_gt b a
+ end).
+ assert (Hcmp := spec_ww_compare a b);destruct (ww_compare a b).
+ Spec_ww_to_Z b;rewrite Hcmp.
+ apply Zis_gcd_for_euclid with 1;zarith.
+ ring_simplify ([[b]] - 1 * [[b]]). apply Zis_gcd_0;zarith.
+ apply Zis_gcd_sym;apply spec_ww_gcd_gt;zarith.
+ apply spec_ww_gcd_gt;zarith.
+ Qed.
+
+End GenDiv.
+
diff --git a/theories/Ints/num/GenDivn1.v b/theories/Ints/num/GenDivn1.v
new file mode 100644
index 0000000000..4b54d825d1
--- /dev/null
+++ b/theories/Ints/num/GenDivn1.v
@@ -0,0 +1,489 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZDivModAux.
+Require Import ZPowerAux.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section GENDIVN1.
+
+ Variable w : Set.
+ Variable w_digits : positive.
+ Variable w_0 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_head0 : w -> N.
+ Variable w_add_mul_div : positive -> w -> w -> w.
+ Variable w_div21 : w -> w -> w -> w * w.
+
+ (* ** For proofs ** *)
+ Variable w_to_Z : w -> Z.
+
+ Notation wB := (base w_digits).
+
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[! n | x !]" := (gen_to_Z w_digits w_to_Z n x)
+ (at level 0, x at level 99).
+ Notation "[[ x ]]" := (zn2z_to_Z wB w_to_Z x) (at level 0, x at level 99).
+
+ Variable spec_to_Z : forall x, 0 <= [| x |] < wB.
+ Variable spec_0 : [|w_0|] = 0.
+ Variable spec_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_head0 : forall x, 0 < [|x|] ->
+ wB/ 2 <= 2 ^ (Z_of_N (w_head0 x)) * [|x|] < wB.
+ Variable spec_add_mul_div : forall x y p,
+ Zpos p < Zpos w_digits ->
+ [| w_add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos w_digits) - (Zpos p)))) mod wB.
+ Variable spec_div21 : forall a1 a2 b,
+ wB/2 <= [|b|] ->
+ [|a1|] < [|b|] ->
+ let (q,r) := w_div21 a1 a2 b in
+ [|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+
+ Section DIVAUX.
+ Variable b2p : w.
+ Variable b2p_le : wB/2 <= [|b2p|].
+
+ Definition gen_divn1_0_aux n (divn1: w -> word w n -> word w n * w) r h :=
+ let (hh,hl) := gen_split w_0 n h in
+ let (qh,rh) := divn1 r hh in
+ let (ql,rl) := divn1 rh hl in
+ (gen_WW w_WW n qh ql, rl).
+
+ Fixpoint gen_divn1_0 (n:nat) : w -> word w n -> word w n * w :=
+ match n return w -> word w n -> word w n * w with
+ | O => fun r x => w_div21 r x b2p
+ | S n => gen_divn1_0_aux n (gen_divn1_0 n)
+ end.
+
+ Lemma spec_split : forall (n : nat) (x : zn2z (word w n)),
+ let (h, l) := gen_split w_0 n x in
+ [!S n | x!] = [!n | h!] * gen_wB w_digits n + [!n | l!].
+ Proof (spec_gen_split w_0 w_digits w_to_Z spec_0).
+
+ Lemma spec_gen_divn1_0 : forall n r a,
+ [|r|] < [|b2p|] ->
+ let (q,r') := gen_divn1_0 n r a in
+ [|r|] * gen_wB w_digits n + [!n|a!] = [!n|q!] * [|b2p|] + [|r'|] /\
+ 0 <= [|r'|] < [|b2p|].
+ Proof.
+ induction n;intros.
+ exact (spec_div21 a b2p_le H).
+ unfold gen_divn1_0, gen_divn1_0_aux;fold gen_divn1_0.
+ assert (H1 := spec_split n a);destruct (gen_split w_0 n a) as (hh,hl).
+ rewrite H1.
+ assert (H2 := IHn r hh H);destruct (gen_divn1_0 n r hh) as (qh,rh).
+ destruct H2.
+ assert ([|rh|] < [|b2p|]). omega.
+ assert (H4 := IHn rh hl H3);destruct (gen_divn1_0 n rh hl) as (ql,rl).
+ destruct H4;split;trivial.
+ rewrite spec_gen_WW;trivial.
+ rewrite <- gen_wB_wwB.
+ rewrite Zmult_assoc;rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ rewrite H0;rewrite Zmult_plus_distr_l;rewrite <- Zplus_assoc.
+ rewrite H4;ring.
+ Qed.
+
+ Definition gen_modn1_0_aux n (modn1:w -> word w n -> w) r h :=
+ let (hh,hl) := gen_split w_0 n h in modn1 (modn1 r hh) hl.
+
+ Fixpoint gen_modn1_0 (n:nat) : w -> word w n -> w :=
+ match n return w -> word w n -> w with
+ | O => fun r x => snd (w_div21 r x b2p)
+ | S n => gen_modn1_0_aux n (gen_modn1_0 n)
+ end.
+
+ Lemma spec_gen_modn1_0 : forall n r x,
+ gen_modn1_0 n r x = snd (gen_divn1_0 n r x).
+ Proof.
+ induction n;simpl;intros;trivial.
+ unfold gen_modn1_0_aux, gen_divn1_0_aux.
+ destruct (gen_split w_0 n x) as (hh,hl).
+ rewrite (IHn r hh).
+ destruct (gen_divn1_0 n r hh) as (qh,rh);simpl.
+ rewrite IHn. destruct (gen_divn1_0 n rh hl);trivial.
+ Qed.
+
+ Variable p : positive.
+ Variable p_bounded : Zpos p < Zpos w_digits.
+
+ Lemma spec_add_mul_divp : forall x y,
+ [| w_add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos w_digits) - (Zpos p)))) mod wB.
+ Proof.
+ intros;apply spec_add_mul_div;auto.
+ Qed.
+
+ Definition gen_divn1_p_aux n
+ (divn1 : w -> word w n -> word w n -> word w n * w) r h l :=
+ let (hh,hl) := gen_split w_0 n h in
+ let (lh,ll) := gen_split w_0 n l in
+ let (qh,rh) := divn1 r hh hl in
+ let (ql,rl) := divn1 rh hl lh in
+ (gen_WW w_WW n qh ql, rl).
+
+ Fixpoint gen_divn1_p (n:nat) : w -> word w n -> word w n -> word w n * w :=
+ match n return w -> word w n -> word w n -> word w n * w with
+ | O => fun r h l => w_div21 r (w_add_mul_div p h l) b2p
+ | S n => gen_divn1_p_aux n (gen_divn1_p n)
+ end.
+
+ Lemma p_lt_gen_digits : forall n, Zpos p < Zpos (gen_digits w_digits n).
+ Proof.
+ induction n;simpl. destruct p_bounded;trivial.
+ assert (0 < Zpos p). unfold Zlt;reflexivity.
+ rewrite Zpos_xO;auto with zarith.
+ Qed.
+
+ Lemma spec_gen_divn1_p : forall n r h l,
+ [|r|] < [|b2p|] ->
+ let (q,r') := gen_divn1_p n r h l in
+ [|r|] * gen_wB w_digits n +
+ ([!n|h!]*2^(Zpos p) +
+ [!n|l!] / (2^(Zpos(gen_digits w_digits n) - Zpos p)))
+ mod gen_wB w_digits n = [!n|q!] * [|b2p|] + [|r'|] /\
+ 0 <= [|r'|] < [|b2p|].
+ Proof.
+ induction n;intros.
+ unfold gen_divn1_p, gen_divn1_p_aux, gen_to_Z, gen_wB, gen_digits.
+ rewrite <- spec_add_mul_divp.
+ exact (spec_div21 (w_add_mul_div p h l) b2p_le H).
+ unfold gen_divn1_p,gen_divn1_p_aux;fold gen_divn1_p.
+ assert (H1 := spec_split n h);destruct (gen_split w_0 n h) as (hh,hl).
+ rewrite H1. rewrite <- gen_wB_wwB.
+ assert (H2 := spec_split n l);destruct (gen_split w_0 n l) as (lh,ll).
+ rewrite H2.
+ replace ([|r|] * (gen_wB w_digits n * gen_wB w_digits n) +
+ (([!n|hh!] * gen_wB w_digits n + [!n|hl!]) * 2 ^ Zpos p +
+ ([!n|lh!] * gen_wB w_digits n + [!n|ll!]) /
+ 2^(Zpos (gen_digits w_digits (S n)) - Zpos p)) mod
+ (gen_wB w_digits n * gen_wB w_digits n)) with
+ (([|r|] * gen_wB w_digits n + ([!n|hh!] * 2^Zpos p +
+ [!n|hl!] / 2^(Zpos (gen_digits w_digits n) - Zpos p)) mod
+ gen_wB w_digits n) * gen_wB w_digits n +
+ ([!n|hl!] * 2^Zpos p +
+ [!n|lh!] / 2^(Zpos (gen_digits w_digits n) - Zpos p)) mod
+ gen_wB w_digits n).
+ generalize (IHn r hh hl H);destruct (gen_divn1_p n r hh hl) as (qh,rh);
+ intros (H3,H4);rewrite H3.
+ assert ([|rh|] < [|b2p|]). omega.
+ replace (([!n|qh!] * [|b2p|] + [|rh|]) * gen_wB w_digits n +
+ ([!n|hl!] * 2 ^ Zpos p +
+ [!n|lh!] / 2 ^ (Zpos (gen_digits w_digits n) - Zpos p)) mod
+ gen_wB w_digits n) with
+ ([!n|qh!] * [|b2p|] *gen_wB w_digits n + ([|rh|]*gen_wB w_digits n +
+ ([!n|hl!] * 2 ^ Zpos p +
+ [!n|lh!] / 2 ^ (Zpos (gen_digits w_digits n) - Zpos p)) mod
+ gen_wB w_digits n)). 2:ring.
+ generalize (IHn rh hl lh H0);destruct (gen_divn1_p n rh hl lh) as (ql,rl);
+ intros (H5,H6);rewrite H5.
+ split;[rewrite spec_gen_WW;trivial;ring|trivial].
+ assert (Uhh := spec_gen_to_Z w_digits w_to_Z spec_to_Z n hh);
+ unfold gen_wB,base in Uhh.
+ assert (Uhl := spec_gen_to_Z w_digits w_to_Z spec_to_Z n hl);
+ unfold gen_wB,base in Uhl.
+ assert (Ulh := spec_gen_to_Z w_digits w_to_Z spec_to_Z n lh);
+ unfold gen_wB,base in Ulh.
+ assert (Ull := spec_gen_to_Z w_digits w_to_Z spec_to_Z n ll);
+ unfold gen_wB,base in Ull.
+ unfold gen_wB,base.
+ assert (UU:=p_lt_gen_digits n).
+ rewrite Zdiv_shift_r;auto with zarith.
+ 2:change (Zpos (gen_digits w_digits (S n)))
+ with (2*Zpos (gen_digits w_digits n));auto with zarith.
+ replace (2 ^ (Zpos (gen_digits w_digits (S n)) - Zpos p)) with
+ (2^(Zpos (gen_digits w_digits n) - Zpos p)*2^Zpos (gen_digits w_digits n)).
+ rewrite Zdiv_Zmult_compat_r;auto with zarith.
+ rewrite Zmult_plus_distr_l with (p:= 2^Zpos p).
+ pattern ([!n|hl!] * 2^Zpos p) at 2;
+ rewrite (shift_unshift_mod (Zpos(gen_digits w_digits n))(Zpos p)([!n|hl!]));
+ auto with zarith.
+ rewrite Zplus_assoc.
+ replace
+ ([!n|hh!] * 2^Zpos (gen_digits w_digits n)* 2^Zpos p +
+ ([!n|hl!] / 2^(Zpos (gen_digits w_digits n)-Zpos p)*
+ 2^Zpos(gen_digits w_digits n)))
+ with
+ (([!n|hh!] *2^Zpos p + gen_to_Z w_digits w_to_Z n hl /
+ 2^(Zpos (gen_digits w_digits n)-Zpos p))
+ * 2^Zpos(gen_digits w_digits n));try (ring;fail).
+ rewrite <- Zplus_assoc.
+ rewrite <- (Zmod_shift_r (Zpos p));auto with zarith.
+ replace
+ (2 ^ Zpos (gen_digits w_digits n) * 2 ^ Zpos (gen_digits w_digits n)) with
+ (2 ^ (Zpos (gen_digits w_digits n) + Zpos (gen_digits w_digits n))).
+ rewrite (Zmod_shift_r (Zpos (gen_digits w_digits n)));auto with zarith.
+ replace (2 ^ (Zpos (gen_digits w_digits n) + Zpos (gen_digits w_digits n)))
+ with (2^Zpos(gen_digits w_digits n) *2^Zpos(gen_digits w_digits n)).
+ rewrite (Zmult_comm (([!n|hh!] * 2 ^ Zpos p +
+ [!n|hl!] / 2 ^ (Zpos (gen_digits w_digits n) - Zpos p)))).
+ rewrite Zmod_Zmult_compat_l;auto with zarith.
+ ring.
+ rewrite Zpower_exp;auto with zarith.
+ assert (0 < Zpos (gen_digits w_digits n)). unfold Zlt;reflexivity.
+ auto with zarith.
+ apply Z_mod_lt;auto with zarith.
+ rewrite Zpower_exp;auto with zarith.
+ split;auto with zarith.
+ apply Zdiv_lt_upper_bound;auto with zarith.
+ rewrite <- Zpower_exp;auto with zarith.
+ replace (Zpos p + (Zpos (gen_digits w_digits n) - Zpos p)) with
+ (Zpos(gen_digits w_digits n));auto with zarith.
+ assert (0 < Zpos p). unfold Zlt;reflexivity. auto with zarith.
+ rewrite <- Zpower_exp;auto with zarith.
+ replace (Zpos (gen_digits w_digits (S n)) - Zpos p) with
+ (Zpos (gen_digits w_digits n) - Zpos p +
+ Zpos (gen_digits w_digits n));trivial.
+ change (Zpos (gen_digits w_digits (S n))) with
+ (2*Zpos (gen_digits w_digits n)). ring.
+ Qed.
+
+ Definition gen_modn1_p_aux n (modn1 : w -> word w n -> word w n -> w) r h l:=
+ let (hh,hl) := gen_split w_0 n h in
+ let (lh,ll) := gen_split w_0 n l in
+ modn1 (modn1 r hh hl) hl lh.
+
+ Fixpoint gen_modn1_p (n:nat) : w -> word w n -> word w n -> w :=
+ match n return w -> word w n -> word w n -> w with
+ | O => fun r h l => snd (w_div21 r (w_add_mul_div p h l) b2p)
+ | S n => gen_modn1_p_aux n (gen_modn1_p n)
+ end.
+
+ Lemma spec_gen_modn1_p : forall n r h l ,
+ gen_modn1_p n r h l = snd (gen_divn1_p n r h l).
+ Proof.
+ induction n;simpl;intros;trivial.
+ unfold gen_modn1_p_aux, gen_divn1_p_aux.
+ destruct(gen_split w_0 n h)as(hh,hl);destruct(gen_split w_0 n l) as (lh,ll).
+ rewrite (IHn r hh hl);destruct (gen_divn1_p n r hh hl) as (qh,rh).
+ rewrite IHn;simpl;destruct (gen_divn1_p n rh hl lh);trivial.
+ Qed.
+
+ End DIVAUX.
+
+ Fixpoint hight (n:nat) : word w n -> w :=
+ match n return word w n -> w with
+ | O => fun a => a
+ | S n =>
+ fun (a:zn2z (word w n)) =>
+ match a with
+ | W0 => w_0
+ | WW h l => hight n h
+ end
+ end.
+
+ Lemma spec_gen_digits:forall n, Zpos w_digits <= Zpos (gen_digits w_digits n).
+ Proof.
+ induction n;simpl;auto with zarith.
+ change (Zpos (xO (gen_digits w_digits n))) with
+ (2*Zpos (gen_digits w_digits n)).
+ assert (0 < Zpos w_digits);auto with zarith.
+ exact (refl_equal Lt).
+ Qed.
+
+ Lemma spec_hight : forall n (x:word w n),
+ [|hight n x|] = [!n|x!] / 2^(Zpos (gen_digits w_digits n) - Zpos w_digits).
+ Proof.
+ induction n;intros.
+ unfold hight,gen_digits,gen_to_Z.
+ replace (Zpos w_digits - Zpos w_digits) with 0;try ring.
+ simpl. rewrite <- (Zdiv_unique [|x|] 1 [|x|] 0);auto with zarith.
+ assert (U2 := spec_gen_digits n).
+ assert (U3 : 0 < Zpos w_digits). exact (refl_equal Lt).
+ destruct x;unfold hight;fold hight.
+ unfold gen_to_Z,zn2z_to_Z;rewrite spec_0.
+ rewrite Zdiv_0;trivial.
+ apply Zpower_lt_0;auto with zarith.
+ change (Zpos (gen_digits w_digits (S n))) with
+ (2*Zpos (gen_digits w_digits n)).
+ auto with zarith.
+ assert (U0 := spec_gen_to_Z w_digits w_to_Z spec_to_Z n w0);
+ assert (U1 := spec_gen_to_Z w_digits w_to_Z spec_to_Z n w1).
+ unfold gen_to_Z,zn2z_to_Z;fold (gen_to_Z w_digits w_to_Z).
+ unfold gen_wB,base;rewrite Zdiv_shift_r;auto with zarith.
+ replace (2 ^ (Zpos (gen_digits w_digits (S n)) - Zpos w_digits)) with
+ (2^(Zpos (gen_digits w_digits n) - Zpos w_digits) *
+ 2^Zpos (gen_digits w_digits n)).
+ rewrite Zdiv_Zmult_compat_r;auto with zarith.
+ rewrite <- Zpower_exp;auto with zarith.
+ replace (Zpos (gen_digits w_digits n) - Zpos w_digits +
+ Zpos (gen_digits w_digits n)) with
+ (Zpos (gen_digits w_digits (S n)) - Zpos w_digits);trivial.
+ change (Zpos (gen_digits w_digits (S n))) with
+ (2*Zpos (gen_digits w_digits n));ring.
+ change (Zpos (gen_digits w_digits (S n))) with
+ (2*Zpos (gen_digits w_digits n)); auto with zarith.
+ Qed.
+
+ Definition gen_divn1 (n:nat) (a:word w n) (b:w) :=
+ match w_head0 b with
+ | N0 => gen_divn1_0 b n w_0 a
+ | Npos p =>
+ let b2p := w_add_mul_div p b w_0 in
+ let ha := hight n a in
+ let k := Pminus w_digits p in
+ let lsr_n := w_add_mul_div k w_0 in
+ let r0 := w_add_mul_div p w_0 ha in
+ let (q,r) := gen_divn1_p b2p p n r0 a (gen_0 w_0 n) in
+ (q, lsr_n r)
+ end.
+
+ Lemma spec_gen_divn1 : forall n a b,
+ 0 < [|b|] ->
+ let (q,r) := gen_divn1 n a b in
+ [!n|a!] = [!n|q!] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+ Proof.
+ intros n a b H. unfold gen_divn1.
+ assert (H0 := spec_head0 H).
+ destruct (w_head0 b).
+ unfold Z_of_N, Zpower in H0.
+ rewrite Zmult_1_l in H0;destruct H0.
+ rewrite <- spec_0 in H.
+ assert (H2 := spec_gen_divn1_0 H0 n a H).
+ rewrite spec_0 in H2;rewrite Zmult_0_l in H2;rewrite Zplus_0_l in H2.
+ exact H2.
+ unfold Z_of_N in H0.
+ assert (HHHH : 0 < Zpos p). unfold Zlt;reflexivity.
+ assert (Zpos p < Zpos w_digits).
+ destruct (Z_lt_le_dec (Zpos p) (Zpos w_digits));trivial.
+ assert (2 ^ Zpos p < wB).
+ apply Zle_lt_trans with (2 ^ Zpos p * [|b|]);auto with zarith.
+ replace (2 ^ Zpos p) with (2^Zpos p * 1);try (ring;fail).
+ apply Zmult_le_compat;auto with zarith.
+ assert (wB <= 2^Zpos p).
+ unfold base;apply Zpower_le_monotone;auto with zarith. omega.
+ assert ([|w_add_mul_div p b w_0|] = 2 ^ Zpos p * [|b|]).
+ assert (H2 := spec_add_mul_div b w_0 H1).
+ rewrite spec_0 in H2;rewrite Zdiv_0 in H2;
+ rewrite Zplus_0_r in H2;rewrite Zmult_comm in H2.
+ rewrite Zmod_def_small in H2;auto with zarith.
+ apply Zpower_lt_0;auto with zarith.
+ destruct H0.
+ assert (H4 := spec_to_Z (hight n a)).
+ assert
+ ([|w_add_mul_div p w_0 (hight n a)|]<[|w_add_mul_div p b w_0|]).
+ rewrite H2.
+ rewrite spec_add_mul_div;auto with zarith.
+ rewrite spec_0;rewrite Zmult_0_l;rewrite Zplus_0_l.
+ assert (([|hight n a|]/2^(Zpos w_digits - Zpos p)) < wB).
+ apply Zdiv_lt_upper_bound;auto with zarith.
+ apply Zlt_le_trans with wB;auto with zarith.
+ pattern wB at 1;replace wB with (wB*1);try ring.
+ apply Zmult_le_compat;auto with zarith.
+ assert (H5 := Zpower_lt_0 2 (Zpos w_digits - Zpos p));
+ auto with zarith.
+ rewrite Zmod_def_small;auto with zarith.
+ apply Zdiv_lt_upper_bound;auto with zarith.
+ apply Zlt_le_trans with wB;auto with zarith.
+ apply Zle_trans with (2 ^ Zpos p * [|b|] * 2).
+ rewrite <- wB_div_2;auto with zarith.
+ apply Zmult_le_compat;auto with zarith.
+ pattern 2 at 1;rewrite <- Zpower_exp_1.
+ apply Zpower_le_monotone;split;auto with zarith.
+ rewrite <- H2 in H0.
+ assert (H6:= spec_gen_divn1_p H0 H1 n a (gen_0 w_0 n) H5).
+ destruct (gen_divn1_p (w_add_mul_div p b w_0) p n
+ (w_add_mul_div p w_0 (hight n a)) a
+ (gen_0 w_0 n)) as (q,r).
+ assert (U:= spec_gen_digits n).
+ rewrite spec_gen_0 in H6;trivial;rewrite Zdiv_0 in H6.
+ rewrite Zplus_0_r in H6.
+ rewrite spec_add_mul_div in H6;auto with zarith.
+ rewrite spec_0 in H6;rewrite Zmult_0_l in H6;rewrite Zplus_0_l in H6.
+ assert (([|hight n a|] / 2 ^ (Zpos w_digits - Zpos p)) mod wB
+ = [!n|a!] / 2^(Zpos (gen_digits w_digits n) - Zpos p)).
+ rewrite Zmod_def_small;auto with zarith.
+ rewrite spec_hight. rewrite Zdiv_Zdiv;auto with zarith.
+ rewrite <- Zpower_exp;auto with zarith.
+ replace (Zpos (gen_digits w_digits n) - Zpos w_digits +
+ (Zpos w_digits - Zpos p))
+ with (Zpos (gen_digits w_digits n) - Zpos p);trivial;ring.
+ assert (H7 := Zpower_lt_0 2 (Zpos w_digits - Zpos p));auto with zarith.
+ split;auto with zarith.
+ apply Zle_lt_trans with ([|hight n a|]);auto with zarith.
+ apply Zdiv_le_upper_bound;auto with zarith.
+ pattern ([|hight n a|]) at 1;rewrite <- Zmult_1_r.
+ apply Zmult_le_compat;auto with zarith.
+ rewrite H7 in H6;unfold gen_wB,base in H6.
+ rewrite <- shift_unshift_mod in H6;auto with zarith.
+ rewrite H2 in H6.
+ assert ([|w_add_mul_div (w_digits - p) w_0 r|] = [|r|]/2^Zpos p).
+ rewrite spec_add_mul_div.
+ rewrite spec_0;rewrite Zmult_0_l;rewrite Zplus_0_l.
+ replace (Zpos w_digits - Zpos (w_digits - p)) with (Zpos p).
+ rewrite Zmod_def_small;auto with zarith.
+ assert (H8 := spec_to_Z r).
+ split;auto with zarith.
+ apply Zle_lt_trans with ([|r|]);auto with zarith.
+ apply Zdiv_le_upper_bound;auto with zarith.
+ pattern ([|r|]) at 1;rewrite <- Zmult_1_r.
+ apply Zmult_le_compat;auto with zarith.
+ assert (H9 := Zpower_lt_0 2 (Zpos p));auto with zarith.
+ rewrite Zpos_minus;auto with zarith.
+ rewrite Zpos_minus;auto with zarith.
+ destruct H6.
+ split.
+ rewrite <- (Z_div_mult [!n|a!] (2^Zpos p));auto with zarith.
+ rewrite H8;rewrite H6.
+ replace ([!n|q!] * (2 ^ Zpos p * [|b|])) with ([!n|q!] *[|b|] * 2^Zpos p);
+ try (ring;fail).
+ rewrite Z_div_plus_l;auto with zarith.
+ assert (H10 := spec_to_Z (w_add_mul_div (w_digits - p) w_0 r));split;
+ auto with zarith.
+ rewrite H8.
+ apply Zdiv_lt_upper_bound;auto with zarith.
+ rewrite Zmult_comm;auto with zarith.
+ exact (spec_gen_to_Z w_digits w_to_Z spec_to_Z n a).
+ apply Zpower_lt_0;auto with zarith.
+ Qed.
+
+ Definition gen_modn1 (n:nat) (a:word w n) (b:w) :=
+ match w_head0 b with
+ | N0 => gen_modn1_0 b n w_0 a
+ | Npos p =>
+ let b2p := w_add_mul_div p b w_0 in
+ let ha := hight n a in
+ let k := Pminus w_digits p in
+ let lsr_n := w_add_mul_div k w_0 in
+ let r0 := w_add_mul_div p w_0 ha in
+ let r := gen_modn1_p b2p p n r0 a (gen_0 w_0 n) in
+ lsr_n r
+ end.
+
+ Lemma spec_gen_modn1_aux : forall n a b,
+ gen_modn1 n a b = snd (gen_divn1 n a b).
+ Proof.
+ intros n a b;unfold gen_divn1,gen_modn1.
+ destruct (w_head0 b).
+ apply spec_gen_modn1_0.
+ rewrite spec_gen_modn1_p.
+ destruct (gen_divn1_p (w_add_mul_div p b w_0) p n
+ (w_add_mul_div p w_0 (hight n a)) a (gen_0 w_0 n));simpl;trivial.
+ Qed.
+
+ Lemma spec_gen_modn1 : forall n a b, 0 < [|b|] ->
+ [|gen_modn1 n a b|] = [!n|a!] mod [|b|].
+ Proof.
+ intros n a b H;assert (H1 := spec_gen_divn1 n a H).
+ assert (H2 := spec_gen_modn1_aux n a b).
+ rewrite H2;destruct (gen_divn1 n a b) as (q,r).
+ simpl;apply Zmod_unique with (gen_to_Z w_digits w_to_Z n q);auto with zarith.
+ destruct H1 as (h1,h2);rewrite h1;ring.
+ Qed.
+
+End GENDIVN1.
diff --git a/theories/Ints/num/GenLift.v b/theories/Ints/num/GenLift.v
new file mode 100644
index 0000000000..14aa869796
--- /dev/null
+++ b/theories/Ints/num/GenLift.v
@@ -0,0 +1,278 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZPowerAux.
+Require Import ZDivModAux.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section GenLift.
+ Variable w : Set.
+ Variable w_0 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_W0 : w -> zn2z w.
+ Variable w_0W : w -> zn2z w.
+ Variable w_compare : w -> w -> comparison.
+ Variable w_head0 : w -> N.
+ Variable w_add_mul_div : positive -> w -> w -> w.
+ Variable w_digits : positive.
+ Variable ww_Digits : positive.
+
+ Definition ww_head0 x :=
+ match x with
+ | W0 => Npos ww_Digits
+ | WW xh xl =>
+ match w_compare w_0 xh with
+ | Eq => Nplus (Npos w_digits) (w_head0 xl)
+ | _ => w_head0 xh
+ end
+ end.
+
+ (* 0 < p < ww_digits *)
+ Definition ww_add_mul_div p x y :=
+ match x, y with
+ | W0, W0 => W0
+ | W0, WW yh yl =>
+ match Pcompare p w_digits Eq with
+ | Eq => w_0W yh
+ | Lt => w_0W (w_add_mul_div p w_0 yh)
+ | Gt =>
+ let n := Pminus p w_digits in
+ w_WW (w_add_mul_div n w_0 yh) (w_add_mul_div n yh yl)
+ end
+ | WW xh xl, W0 =>
+ match Pcompare p w_digits Eq with
+ | Eq => w_W0 xl
+ | Lt => w_WW (w_add_mul_div p xh xl) (w_add_mul_div p xl w_0)
+ | Gt =>
+ let n := Pminus p w_digits in
+ w_W0 (w_add_mul_div n xl w_0)
+ end
+ | WW xh xl, WW yh yl =>
+ match Pcompare p w_digits Eq with
+ | Eq => w_WW xl yh
+ | Lt => w_WW (w_add_mul_div p xh xl) (w_add_mul_div p xl yh)
+ | Gt =>
+ let n := Pminus p w_digits in
+ w_WW (w_add_mul_div n xl yh) (w_add_mul_div n yh yl)
+ end
+ end.
+
+ Section GenProof.
+ Variable w_to_Z : w -> Z.
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_w_W0 : forall h, [[w_W0 h]] = [|h|] * wB.
+ Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
+ Variable spec_compare : forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Variable spec_ww_digits : ww_Digits = xO w_digits.
+ Variable spec_w_head0 : forall x, 0 < [|x|] ->
+ wB/ 2 <= 2 ^ (Z_of_N (w_head0 x)) * [|x|] < wB.
+ Variable spec_w_add_mul_div : forall x y p,
+ Zpos p < Zpos w_digits ->
+ [| w_add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos w_digits) - (Zpos p)))) mod wB.
+
+
+ Hint Resolve div_le_0 div_lt w_to_Z_wwB: lift.
+ Ltac zarith := auto with zarith lift.
+
+ Lemma spec_ww_head0 : forall x, 0 < [[x]] ->
+ wwB/ 2 <= 2 ^ (Z_of_N (ww_head0 x)) * [[x]] < wwB.
+ Proof.
+ rewrite wwB_div_2;rewrite Zmult_comm;rewrite wwB_wBwB.
+ assert (U:= lt_0_wB w_digits); destruct x as [ |xh xl];simpl ww_to_Z;intros H.
+ unfold Zlt in H;discriminate H.
+ assert (H0 := spec_compare w_0 xh);rewrite spec_w_0 in H0.
+ simpl Z_of_N; destruct (w_compare w_0 xh).
+ rewrite <- H0. simpl Zplus. rewrite <- H0 in H;simpl in H.
+ generalize (spec_w_head0 H);destruct (w_head0 xl) as [ |q].
+ intros H1;simpl Zpower in H1;rewrite Zmult_1_l in H1.
+ change (2 ^ Z_of_N (Npos w_digits)) with wB;split;zarith.
+ rewrite Zpower_2; apply Zmult_lt_compat_l;zarith.
+ unfold Z_of_N;intros.
+ change (Zpos(w_digits + q))with (Zpos w_digits + Zpos q);rewrite Zpower_exp.
+ fold wB;rewrite <- Zmult_assoc;split;zarith.
+ rewrite Zpower_2; apply Zmult_lt_compat_l;zarith.
+ intro H2;discriminate H2. intro H2;discriminate H2.
+ assert (H1 := spec_w_head0 H0).
+ split.
+ rewrite Zmult_plus_distr_r;rewrite Zmult_assoc.
+ apply Zle_trans with (2 ^ Z_of_N (w_head0 xh) * [|xh|] * wB).
+ rewrite Zmult_comm;zarith.
+ assert (0 <= 2 ^ Z_of_N (w_head0 xh) * [|xl|]);zarith.
+ assert (H2:=spec_to_Z xl);apply Zmult_le_0_compat;zarith.
+ assert (0<= Z_of_N (w_head0 xh)).
+ case (w_head0 xh);intros;simpl;intro H2;discriminate H2.
+ generalize (Z_of_N (w_head0 xh)) H1 H2;clear H1 H2;intros p H1 H2.
+ assert (Eq1 : 2^p < wB).
+ rewrite <- (Zmult_1_r (2^p));apply Zle_lt_trans with (2^p*[|xh|]);zarith.
+ assert (Eq2: p < Zpos w_digits).
+ destruct (Zle_or_lt (Zpos w_digits) p);trivial;contradict Eq1.
+ apply Zle_not_lt;unfold base;apply Zpower_le_monotone;zarith.
+ assert (Zpos w_digits = p + (Zpos w_digits - p)). ring.
+ rewrite Zpower_2.
+ unfold base at 2;rewrite H3;rewrite Zpower_exp;zarith.
+ rewrite <- Zmult_assoc; apply Zmult_lt_compat_l; zarith.
+ rewrite <- (Zplus_0_r (2^(Zpos w_digits - p)*wB));apply beta_lex_inv;zarith.
+ apply Zmult_lt_reg_r with (2 ^ p); zarith.
+ rewrite <- Zpower_exp;zarith.
+ rewrite Zmult_comm;ring_simplify (Zpos w_digits - p + p);fold wB;zarith.
+ assert (H1 := spec_to_Z xh);zarith.
+ Qed.
+
+ Hint Rewrite Zdiv_0 Zmult_0_l Zplus_0_l Zmult_0_r Zplus_0_r
+ spec_w_W0 spec_w_0W spec_w_WW spec_w_0
+ (wB_div w_digits w_to_Z spec_to_Z)
+ (wB_div_plus w_digits w_to_Z spec_to_Z) : w_rewrite.
+ Ltac w_rewrite := autorewrite with w_rewrite;trivial.
+
+ Lemma spec_ww_add_mul_div_aux : forall xh xl yh yl p,
+ Zpos p < Zpos (xO w_digits) ->
+ [[match (p ?= w_digits)%positive Eq with
+ | Eq => w_WW xl yh
+ | Lt => w_WW (w_add_mul_div p xh xl) (w_add_mul_div p xl yh)
+ | Gt =>
+ let n := (p - w_digits)%positive in
+ w_WW (w_add_mul_div n xl yh) (w_add_mul_div n yh yl)
+ end]] =
+ ([[WW xh xl]] * (2^Zpos p) +
+ [[WW yh yl]] / (2^(Zpos (xO w_digits) - Zpos p))) mod wwB.
+ Proof.
+ intros xh xl yh yl p;assert (HwwB := wwB_pos w_digits).
+ assert (0 < Zpos p). unfold Zlt;reflexivity.
+ replace (Zpos (xO w_digits)) with (Zpos w_digits + Zpos w_digits).
+ 2 : rewrite Zpos_xO;ring.
+ replace (Zpos w_digits + Zpos w_digits - Zpos p) with
+ (Zpos w_digits + (Zpos w_digits - Zpos p)). 2:ring.
+ intros Hp; assert (Hxh := spec_to_Z xh);assert (Hxl:=spec_to_Z xl);
+ assert (Hx := spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW xh xl));
+ simpl in Hx;assert (Hyh := spec_to_Z yh);assert (Hyl:=spec_to_Z yl);
+ assert (Hy:=spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW yh yl));simpl in Hy.
+ case_eq ((p ?= w_digits)%positive Eq);intros;w_rewrite;
+ match goal with
+ | [H: (p ?= w_digits)%positive Eq = Eq |- _] =>
+ let H1:= fresh "H" in
+ (assert (H1 : Zpos p = Zpos w_digits);
+ [ rewrite Pcompare_Eq_eq with (1:= H);trivial
+ | rewrite H1;try rewrite Zminus_diag;try rewrite Zplus_0_r]);
+ fold wB
+ | [H: (p ?= w_digits)%positive Eq = Lt |- _] =>
+ change ((p ?= w_digits)%positive Eq = Lt) with
+ (Zpos p < Zpos w_digits) in H;
+ repeat rewrite spec_w_add_mul_div;zarith
+ | [H: (p ?= w_digits)%positive Eq = Gt |- _] =>
+ change ((p ?= w_digits)%positive Eq=Gt)with(Zpos p > Zpos w_digits) in H;
+ let H1 := fresh "H" in
+ assert (H1 := Zpos_minus _ _ (Zgt_lt _ _ H));
+ replace (Zpos w_digits + (Zpos w_digits - Zpos p)) with
+ (Zpos w_digits - Zpos (p - w_digits));
+ [ repeat rewrite spec_w_add_mul_div;zarith
+ | zarith ]
+ | _ => idtac
+ end;simpl ww_to_Z;w_rewrite;zarith.
+ rewrite Zmult_plus_distr_l;rewrite <- Zmult_assoc;rewrite <- Zplus_assoc.
+ rewrite <- Zpower_2.
+ rewrite <- wwB_wBwB;apply Zmod_unique with [|xh|]. apply lt_0_wwB.
+ exact (spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW xl yh)). ring.
+ rewrite Zmult_plus_distr_l.
+ pattern ([|xl|] * 2 ^ Zpos p) at 2;
+ rewrite shift_unshift_mod with (n:= Zpos w_digits);fold wB;zarith.
+ replace ([|xh|] * wB * 2^Zpos p) with ([|xh|] * 2^Zpos p * wB). 2:ring.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l. rewrite <- Zplus_assoc.
+ unfold base at 5;rewrite <- Zmod_shift_r;zarith.
+ unfold base;rewrite Zmod_shift_r with (b:= Zpos (ww_digits w_digits));
+ fold wB;fold wwB;zarith.
+ rewrite wwB_wBwB;rewrite Zpower_2; rewrite Zmult_mod_distr_r;zarith.
+ unfold ww_digits;rewrite Zpos_xO;zarith. apply Z_mod_lt;zarith.
+ split;zarith. apply Zdiv_lt_upper_bound;zarith.
+ rewrite <- Zpower_exp;zarith.
+ ring_simplify (Zpos p + (Zpos w_digits - Zpos p));fold wB;zarith.
+ pattern wB at 5;replace wB with
+ (2^(Zpos (p - w_digits) + (Zpos w_digits - Zpos (p - w_digits)))).
+ rewrite Zpower_exp;zarith. rewrite Zmult_assoc.
+ rewrite Z_div_plus_l;zarith.
+ rewrite shift_unshift_mod with (a:= [|yh|]) (p:= Zpos (p - w_digits))
+ (n := Zpos w_digits);zarith. fold wB.
+ replace (Zpos p) with (Zpos (p - w_digits) + Zpos w_digits);zarith.
+ rewrite Zpower_exp;zarith. rewrite Zmult_assoc. fold wB.
+ repeat rewrite Zplus_assoc. rewrite <- Zmult_plus_distr_l.
+ repeat rewrite <- Zplus_assoc.
+ unfold base;rewrite Zmod_shift_r with (b:= Zpos (ww_digits w_digits));
+ fold wB;fold wwB;zarith.
+ unfold base;rewrite Zmod_shift_r with (a:= Zpos w_digits)
+ (b:= Zpos w_digits);fold wB;fold wwB;zarith.
+ rewrite wwB_wBwB; rewrite Zpower_2; rewrite Zmult_mod_distr_r;zarith.
+ rewrite Zmult_plus_distr_l.
+ replace ([|xh|] * wB * 2 ^ Zpos (p - w_digits)) with
+ ([|xh|]*2^Zpos(p - w_digits)*wB). 2:ring.
+ repeat rewrite <- Zplus_assoc.
+ rewrite (Zplus_comm ([|xh|] * 2 ^ Zpos (p - w_digits) * wB)).
+ rewrite Z_mod_plus;zarith. rewrite Zmod_mult_0;zarith.
+ unfold base;rewrite <- Zmod_shift_r;zarith. fold base;apply Z_mod_lt;zarith.
+ split;zarith. apply Zdiv_lt_upper_bound;zarith.
+ rewrite <- Zpower_exp;zarith.
+ ring_simplify (Zpos (p - w_digits) + (Zpos w_digits - Zpos (p - w_digits))); fold
+ wB;zarith. unfold ww_digits;rewrite Zpos_xO;zarith.
+ unfold base;rewrite <- Zmod_shift_r;zarith. fold base;apply Z_mod_lt;zarith.
+ split;zarith. apply Zdiv_lt_upper_bound;zarith.
+ rewrite <- Zpower_exp;zarith.
+ ring_simplify (Zpos (p - w_digits) + (Zpos w_digits - Zpos (p - w_digits))); fold
+ wB;zarith.
+ ring_simplify (Zpos (p - w_digits) + (Zpos w_digits - Zpos (p - w_digits))); fold
+ wB;trivial.
+ Qed.
+
+ Lemma spec_ww_add_mul_div : forall x y p,
+ Zpos p < Zpos (xO w_digits) ->
+ [[ ww_add_mul_div p x y ]] =
+ ([[x]] * (2^Zpos p) +
+ [[y]] / (2^(Zpos (xO w_digits) - Zpos p))) mod wwB.
+ Proof.
+ intros x y p H.
+ destruct x as [ |xh xl];
+ [assert (H1 := @spec_ww_add_mul_div_aux w_0 w_0)
+ |assert (H1 := @spec_ww_add_mul_div_aux xh xl)];
+ (destruct y as [ |yh yl];
+ [generalize (H1 w_0 w_0 p H) | generalize (H1 yh yl p H)];
+ clear H1;w_rewrite);simpl ww_add_mul_div.
+ replace [[WW w_0 w_0]] with 0;[w_rewrite|simpl;w_rewrite;trivial].
+ intros Heq;rewrite <- Heq;clear Heq.
+ case_eq ((p ?= w_digits)%positive Eq);w_rewrite;intros;trivial.
+ rewrite (spec_w_add_mul_div w_0 w_0);w_rewrite;zarith.
+ replace [[WW w_0 w_0]] with 0;[w_rewrite|simpl;w_rewrite;trivial].
+ intros Heq;rewrite <- Heq;clear Heq.
+ case_eq ((p ?= w_digits)%positive Eq);w_rewrite;intros;trivial.
+ rewrite (spec_w_add_mul_div w_0 w_0);w_rewrite;zarith.
+ change ((p ?= w_digits)%positive Eq = Gt)with(Zpos p > Zpos w_digits) in H0.
+ rewrite Zpos_minus;zarith. rewrite Zpos_xO in H;zarith.
+ Qed.
+
+ End GenProof.
+
+End GenLift.
+
diff --git a/theories/Ints/num/GenMul.v b/theories/Ints/num/GenMul.v
new file mode 100644
index 0000000000..d303965508
--- /dev/null
+++ b/theories/Ints/num/GenMul.v
@@ -0,0 +1,623 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section GenMul.
+ Variable w : Set.
+ Variable w_0 : w.
+ Variable w_1 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_W0 : w -> zn2z w.
+ Variable w_0W : w -> zn2z w.
+ Variable w_compare : w -> w -> comparison.
+ Variable w_succ : w -> w.
+ Variable w_add_c : w -> w -> carry w.
+ Variable w_add : w -> w -> w.
+ Variable w_sub: w -> w -> w.
+ Variable w_mul_c : w -> w -> zn2z w.
+ Variable w_mul : w -> w -> w.
+ Variable w_square_c : w -> zn2z w.
+ Variable ww_add_c : zn2z w -> zn2z w -> carry (zn2z w).
+ Variable ww_add : zn2z w -> zn2z w -> zn2z w.
+ Variable ww_add_carry : zn2z w -> zn2z w -> zn2z w.
+ Variable ww_sub_c : zn2z w -> zn2z w -> carry (zn2z w).
+ Variable ww_sub : zn2z w -> zn2z w -> zn2z w.
+
+ (* ** Multiplication ** *)
+
+ (* (xh*B+xl) (yh*B + yl)
+ xh*yh = hh = |hhh|hhl|B2
+ xh*yl +xl*yh = cc = |cch|ccl|B
+ xl*yl = ll = |llh|lll
+ *)
+
+ Definition gen_mul_c (cross:w->w->w->w->zn2z w -> zn2z w -> w*zn2z w) x y :=
+ match x, y with
+ | W0, _ => W0
+ | _, W0 => W0
+ | WW xh xl, WW yh yl =>
+ let hh := w_mul_c xh yh in
+ let ll := w_mul_c xl yl in
+ let (wc,cc) := cross xh xl yh yl hh ll in
+ match cc with
+ | W0 => WW (ww_add hh (w_W0 wc)) ll
+ | WW cch ccl =>
+ match ww_add_c (w_W0 ccl) ll with
+ | C0 l => WW (ww_add hh (w_WW wc cch)) l
+ | C1 l => WW (ww_add_carry hh (w_WW wc cch)) l
+ end
+ end
+ end.
+
+ Definition ww_mul_c :=
+ gen_mul_c
+ (fun xh xl yh yl hh ll=>
+ match ww_add_c (w_mul_c xh yl) (w_mul_c xl yh) with
+ | C0 cc => (w_0, cc)
+ | C1 cc => (w_1, cc)
+ end).
+
+ Definition w_2 := w_add w_1 w_1.
+
+ Definition kara_prod xh xl yh yl hh ll :=
+ match ww_add_c hh ll with
+ C0 m =>
+ match w_compare xl xh with
+ Eq => (w_0, m)
+ | Lt =>
+ match w_compare yl yh with
+ Eq => (w_0, m)
+ | Lt => (w_0, ww_sub m (w_mul_c (w_sub xh xl) (w_sub yh yl)))
+ | Gt => match ww_add_c m (w_mul_c (w_sub xh xl) (w_sub yl yh)) with
+ C1 m1 => (w_1, m1) | C0 m1 => (w_0, m1)
+ end
+ end
+ | Gt =>
+ match w_compare yl yh with
+ Eq => (w_0, m)
+ | Lt => match ww_add_c m (w_mul_c (w_sub xl xh) (w_sub yh yl)) with
+ C1 m1 => (w_1, m1) | C0 m1 => (w_0, m1)
+ end
+ | Gt => (w_0, ww_sub m (w_mul_c (w_sub xl xh) (w_sub yl yh)))
+ end
+ end
+ | C1 m =>
+ match w_compare xl xh with
+ Eq => (w_1, m)
+ | Lt =>
+ match w_compare yl yh with
+ Eq => (w_1, m)
+ | Lt => match ww_sub_c m (w_mul_c (w_sub xh xl) (w_sub yh yl)) with
+ C0 m1 => (w_1, m1) | C1 m1 => (w_0, m1)
+ end
+ | Gt => match ww_add_c m (w_mul_c (w_sub xh xl) (w_sub yl yh)) with
+ C1 m1 => (w_2, m1) | C0 m1 => (w_1, m1)
+ end
+ end
+ | Gt =>
+ match w_compare yl yh with
+ Eq => (w_1, m)
+ | Lt => match ww_add_c m (w_mul_c (w_sub xl xh) (w_sub yh yl)) with
+ C1 m1 => (w_2, m1) | C0 m1 => (w_1, m1)
+ end
+ | Gt => match ww_sub_c m (w_mul_c (w_sub xl xh) (w_sub yl yh)) with
+ C1 m1 => (w_0, m1) | C0 m1 => (w_1, m1)
+ end
+ end
+ end
+ end.
+
+ Definition ww_karatsuba_c := gen_mul_c kara_prod.
+
+ Definition ww_mul x y :=
+ match x, y with
+ | W0, _ => W0
+ | _, W0 => W0
+ | WW xh xl, WW yh yl =>
+ let ccl := w_add (w_mul xh yl) (w_mul xl yh) in
+ ww_add (w_W0 ccl) (w_mul_c xl yl)
+ end.
+
+ Definition ww_square_c x :=
+ match x with
+ | W0 => W0
+ | WW xh xl =>
+ let hh := w_square_c xh in
+ let ll := w_square_c xl in
+ let xhxl := w_mul_c xh xl in
+ let (wc,cc) :=
+ match ww_add_c xhxl xhxl with
+ | C0 cc => (w_0, cc)
+ | C1 cc => (w_1, cc)
+ end in
+ match cc with
+ | W0 => WW (ww_add hh (w_W0 wc)) ll
+ | WW cch ccl =>
+ match ww_add_c (w_W0 ccl) ll with
+ | C0 l => WW (ww_add hh (w_WW wc cch)) l
+ | C1 l => WW (ww_add_carry hh (w_WW wc cch)) l
+ end
+ end
+ end.
+
+ Section GenMulAddn1.
+ Variable w_mul_add : w -> w -> w -> w * w.
+
+ Fixpoint gen_mul_add_n1 (n:nat) : word w n -> w -> w -> w * word w n :=
+ match n return word w n -> w -> w -> w * word w n with
+ | O => w_mul_add
+ | S n1 =>
+ let mul_add := gen_mul_add_n1 n1 in
+ fun x y r =>
+ match x with
+ | W0 => (w_0,extend w_0W n1 r)
+ | WW xh xl =>
+ let (rl,l) := mul_add xl y r in
+ let (rh,h) := mul_add xh y rl in
+ (rh, gen_WW w_WW n1 h l)
+ end
+ end.
+
+ End GenMulAddn1.
+
+ Section GenMulAddmn1.
+ Variable wn: Set.
+ Variable extend_n : w -> wn.
+ Variable wn_0W : wn -> zn2z wn.
+ Variable wn_WW : wn -> wn -> zn2z wn.
+ Variable w_mul_add_n1 : wn -> w -> w -> w*wn.
+ Fixpoint gen_mul_add_mn1 (m:nat) :
+ word wn m -> w -> w -> w*word wn m :=
+ match m return word wn m -> w -> w -> w*word wn m with
+ | O => w_mul_add_n1
+ | S m1 =>
+ let mul_add := gen_mul_add_mn1 m1 in
+ fun x y r =>
+ match x with
+ | W0 => (w_0,extend wn_0W m1 (extend_n r))
+ | WW xh xl =>
+ let (rl,l) := mul_add xl y r in
+ let (rh,h) := mul_add xh y rl in
+ (rh, gen_WW wn_WW m1 h l)
+ end
+ end.
+
+ End GenMulAddmn1.
+
+ Definition w_mul_add x y r :=
+ match w_mul_c x y with
+ | W0 => (w_0, r)
+ | WW h l =>
+ match w_add_c l r with
+ | C0 lr => (h,lr)
+ | C1 lr => (w_succ h, lr)
+ end
+ end.
+
+
+ (*Section GenProof. *)
+ Variable w_digits : positive.
+ Variable w_to_Z : w -> Z.
+ Variable more_than_one_bit: 1 < Zpos w_digits.
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[+| c |]" :=
+ (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Notation "[+[ c ]]" :=
+ (interp_carry 1 wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+
+ Notation "[|| x ||]" :=
+ (zn2z_to_Z wwB (ww_to_Z w_digits w_to_Z) x) (at level 0, x at level 99).
+
+ Notation "[! n | x !]" := (gen_to_Z w_digits w_to_Z n x)
+ (at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_1 : [|w_1|] = 1.
+
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_w_W0 : forall h, [[w_W0 h]] = [|h|] * wB.
+ Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
+ Variable spec_w_compare :
+ forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Variable spec_w_succ : forall x, [|w_succ x|] = ([|x|] + 1) mod wB.
+ Variable spec_w_add_c : forall x y, [+|w_add_c x y|] = [|x|] + [|y|].
+ Variable spec_w_add : forall x y, [|w_add x y|] = ([|x|] + [|y|]) mod wB.
+ Variable spec_w_sub : forall x y, [|w_sub x y|] = ([|x|] - [|y|]) mod wB.
+
+ Variable spec_w_mul_c : forall x y, [[ w_mul_c x y ]] = [|x|] * [|y|].
+ Variable spec_w_mul : forall x y, [|w_mul x y|] = ([|x|] * [|y|]) mod wB.
+ Variable spec_w_square_c : forall x, [[ w_square_c x]] = [|x|] * [|x|].
+
+ Variable spec_ww_add_c : forall x y, [+[ww_add_c x y]] = [[x]] + [[y]].
+ Variable spec_ww_add : forall x y, [[ww_add x y]] = ([[x]] + [[y]]) mod wwB.
+ Variable spec_ww_add_carry :
+ forall x y, [[ww_add_carry x y]] = ([[x]] + [[y]] + 1) mod wwB.
+ Variable spec_ww_sub : forall x y, [[ww_sub x y]] = ([[x]] - [[y]]) mod wwB.
+ Variable spec_ww_sub_c : forall x y, [-[ww_sub_c x y]] = [[x]] - [[y]].
+
+
+ Lemma spec_ww_to_Z : forall x, 0 <= [[x]] < wwB.
+ Proof. intros x;apply spec_ww_to_Z;auto. Qed.
+
+ Lemma spec_ww_to_Z_wBwB : forall x, 0 <= [[x]] < wB^2.
+ Proof. rewrite <- wwB_wBwB;apply spec_ww_to_Z. Qed.
+
+ Hint Resolve spec_ww_to_Z spec_ww_to_Z_wBwB : mult.
+ Ltac zarith := auto with zarith mult.
+
+ Lemma wBwB_lex: forall a b c d,
+ a * wB^2 + [[b]] <= c * wB^2 + [[d]] ->
+ a <= c.
+ Proof.
+ intros a b c d H; apply beta_lex with [[b]] [[d]] (wB^2);zarith.
+ Qed.
+
+ Lemma wBwB_lex_inv: forall a b c d,
+ a < c ->
+ a * wB^2 + [[b]] < c * wB^2 + [[d]].
+ Proof.
+ intros a b c d H; apply beta_lex_inv; zarith.
+ Qed.
+
+ Lemma sum_mul_carry : forall xh xl yh yl wc cc,
+ [|wc|]*wB^2 + [[cc]] = [|xh|] * [|yl|] + [|xl|] * [|yh|] ->
+ 0 <= [|wc|] <= 1.
+ Proof.
+ intros.
+ apply (sum_mul_carry [|xh|] [|xl|] [|yh|] [|yl|] [|wc|][[cc]] wB);zarith.
+ apply wB_pos.
+ Qed.
+
+ Theorem mult_add_ineq: forall xH yH crossH,
+ 0 <= [|xH|] * [|yH|] + [|crossH|] < wwB.
+ Proof.
+ intros;rewrite wwB_wBwB;apply mult_add_ineq;zarith.
+ Qed.
+
+ Hint Resolve mult_add_ineq : mult.
+
+ Lemma spec_mul_aux : forall xh xl yh yl wc (cc:zn2z w) hh ll,
+ [[hh]] = [|xh|] * [|yh|] ->
+ [[ll]] = [|xl|] * [|yl|] ->
+ [|wc|]*wB^2 + [[cc]] = [|xh|] * [|yl|] + [|xl|] * [|yh|] ->
+ [||match cc with
+ | W0 => WW (ww_add hh (w_W0 wc)) ll
+ | WW cch ccl =>
+ match ww_add_c (w_W0 ccl) ll with
+ | C0 l => WW (ww_add hh (w_WW wc cch)) l
+ | C1 l => WW (ww_add_carry hh (w_WW wc cch)) l
+ end
+ end||] = ([|xh|] * wB + [|xl|]) * ([|yh|] * wB + [|yl|]).
+ Proof.
+ intros;assert (U1 := wB_pos w_digits).
+ replace (([|xh|] * wB + [|xl|]) * ([|yh|] * wB + [|yl|])) with
+ ([|xh|]*[|yh|]*wB^2 + ([|xh|]*[|yl|] + [|xl|]*[|yh|])*wB + [|xl|]*[|yl|]).
+ 2:ring. rewrite <- H1;rewrite <- H;rewrite <- H0.
+ assert (H2 := sum_mul_carry _ _ _ _ _ _ H1).
+ destruct cc as [ | cch ccl]; simpl zn2z_to_Z; simpl ww_to_Z.
+ rewrite spec_ww_add;rewrite spec_w_W0;rewrite Zmod_def_small;
+ rewrite wwB_wBwB. ring.
+ rewrite <- (Zplus_0_r ([|wc|]*wB));rewrite H;apply mult_add_ineq3;zarith.
+ simpl ww_to_Z in H1. assert (U:=spec_to_Z cch).
+ assert ([|wc|]*wB + [|cch|] <= 2*wB - 3).
+ destruct (Z_le_gt_dec ([|wc|]*wB + [|cch|]) (2*wB - 3));trivial.
+ assert ([|xh|] * [|yl|] + [|xl|] * [|yh|] <= (2*wB - 4)*wB + 2).
+ ring_simplify ((2*wB - 4)*wB + 2).
+ assert (H4 := Zmult_lt_b _ _ _ (spec_to_Z xh) (spec_to_Z yl)).
+ assert (H5 := Zmult_lt_b _ _ _ (spec_to_Z xl) (spec_to_Z yh)).
+ omega.
+ generalize H3;clear H3;rewrite <- H1.
+ rewrite Zplus_assoc; rewrite Zpower_2; rewrite Zmult_assoc;
+ rewrite <- Zmult_plus_distr_l.
+ assert (((2 * wB - 4) + 2)*wB <= ([|wc|] * wB + [|cch|])*wB).
+ apply Zmult_le_compat;zarith.
+ rewrite Zmult_plus_distr_l in H3.
+ intros. assert (U2 := spec_to_Z ccl);omega.
+ generalize (spec_ww_add_c (w_W0 ccl) ll);destruct (ww_add_c (w_W0 ccl) ll)
+ as [l|l];unfold interp_carry;rewrite spec_w_W0;try rewrite Zmult_1_l;
+ simpl zn2z_to_Z;
+ try rewrite spec_ww_add;try rewrite spec_ww_add_carry;rewrite spec_w_WW;
+ rewrite Zmod_def_small;rewrite wwB_wBwB;intros.
+ rewrite H4;ring. rewrite H;apply mult_add_ineq2;zarith.
+ rewrite Zplus_assoc;rewrite Zmult_plus_distr_l.
+ rewrite Zmult_1_l;rewrite <- Zplus_assoc;rewrite H4;ring.
+ repeat rewrite <- Zplus_assoc;rewrite H;apply mult_add_ineq2;zarith.
+ Qed.
+
+ Lemma spec_gen_mul_c : forall cross:w->w->w->w->zn2z w -> zn2z w -> w*zn2z w,
+ (forall xh xl yh yl hh ll,
+ [[hh]] = [|xh|]*[|yh|] ->
+ [[ll]] = [|xl|]*[|yl|] ->
+ let (wc,cc) := cross xh xl yh yl hh ll in
+ [|wc|]*wwB + [[cc]] = [|xh|]*[|yl|] + [|xl|]*[|yh|]) ->
+ forall x y, [||gen_mul_c cross x y||] = [[x]] * [[y]].
+ Proof.
+ intros cross Hcross x y;destruct x as [ |xh xl];simpl;trivial.
+ destruct y as [ |yh yl];simpl. rewrite Zmult_0_r;trivial.
+ assert (H1:= spec_w_mul_c xh yh);assert (H2:= spec_w_mul_c xl yl).
+ generalize (Hcross _ _ _ _ _ _ H1 H2).
+ destruct (cross xh xl yh yl (w_mul_c xh yh) (w_mul_c xl yl)) as (wc,cc).
+ intros;apply spec_mul_aux;trivial.
+ rewrite <- wwB_wBwB;trivial.
+ Qed.
+
+ Lemma spec_ww_mul_c : forall x y, [||ww_mul_c x y||] = [[x]] * [[y]].
+ Proof.
+ intros x y;unfold ww_mul_c;apply spec_gen_mul_c.
+ intros xh xl yh yl hh ll H1 H2.
+ generalize (spec_ww_add_c (w_mul_c xh yl) (w_mul_c xl yh));
+ destruct (ww_add_c (w_mul_c xh yl) (w_mul_c xl yh)) as [c|c];
+ unfold interp_carry;repeat rewrite spec_w_mul_c;intros H;
+ (rewrite spec_w_0 || rewrite spec_w_1);rewrite H;ring.
+ Qed.
+
+ Lemma spec_w_2: [|w_2|] = 2.
+ unfold w_2; rewrite spec_w_add; rewrite spec_w_1; simpl.
+ apply Zmod_def_small; split; auto with zarith.
+ rewrite <- (Zpower_exp_1 2); unfold base; apply Zpower_lt_monotone; auto with zarith.
+ Qed.
+
+ Lemma kara_prod_aux : forall xh xl yh yl,
+ xh*yh + xl*yl - (xh-xl)*(yh-yl) = xh*yl + xl*yh.
+ Proof. intros;ring. Qed.
+
+ Lemma spec_kara_prod : forall xh xl yh yl hh ll,
+ [[hh]] = [|xh|]*[|yh|] ->
+ [[ll]] = [|xl|]*[|yl|] ->
+ let (wc,cc) := kara_prod xh xl yh yl hh ll in
+ [|wc|]*wwB + [[cc]] = [|xh|]*[|yl|] + [|xl|]*[|yh|].
+ Proof.
+ intros xh xl yh yl hh ll H H0; rewrite <- kara_prod_aux;
+ rewrite <- H; rewrite <- H0; unfold kara_prod.
+ assert (Hxh := (spec_to_Z xh)); assert (Hxl := (spec_to_Z xl));
+ assert (Hyh := (spec_to_Z yh)); assert (Hyl := (spec_to_Z yl)).
+ generalize (spec_ww_add_c hh ll); case (ww_add_c hh ll);
+ intros z Hz; rewrite <- Hz; unfold interp_carry; assert (Hz1 := (spec_ww_to_Z z)).
+ generalize (spec_w_compare xl xh); case (w_compare xl xh); intros Hxlh;
+ try rewrite Hxlh; try rewrite spec_w_0; try (ring; fail).
+ generalize (spec_w_compare yl yh); case (w_compare yl yh); intros Hylh;
+ try rewrite Hylh; try rewrite spec_w_0; try (ring; fail).
+ repeat (rewrite spec_ww_sub || rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ split; auto with zarith.
+ simpl in Hz; rewrite Hz; rewrite H; rewrite H0.
+ rewrite kara_prod_aux; apply Zplus_le_0_compat; apply Zmult_le_0_compat; auto with zarith.
+ apply Zle_lt_trans with ([[z]]-0); auto with zarith.
+ unfold Zminus; apply Zplus_le_compat_l; apply Zle_left_rev; simpl; rewrite Zopp_involutive.
+ apply Zmult_le_0_compat; auto with zarith.
+ match goal with |- context[ww_add_c ?x ?y] =>
+ generalize (spec_ww_add_c x y); case (ww_add_c x y); try rewrite spec_w_0;
+ intros z1 Hz2
+ end.
+ simpl in Hz2; rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ rewrite spec_w_1; unfold interp_carry in Hz2; rewrite Hz2;
+ repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ generalize (spec_w_compare yl yh); case (w_compare yl yh); intros Hylh;
+ try rewrite Hylh; try rewrite spec_w_0; try (ring; fail).
+ match goal with |- context[ww_add_c ?x ?y] =>
+ generalize (spec_ww_add_c x y); case (ww_add_c x y); try rewrite spec_w_0;
+ intros z1 Hz2
+ end.
+ simpl in Hz2; rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ rewrite spec_w_1; unfold interp_carry in Hz2; rewrite Hz2;
+ repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ repeat (rewrite spec_ww_sub || rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ split.
+ match goal with |- context[(?x - ?y) * (?z - ?t)] =>
+ replace ((x - y) * (z - t)) with ((y - x) * (t - z)); [idtac | ring]
+ end.
+ simpl in Hz; rewrite Hz; rewrite H; rewrite H0.
+ rewrite kara_prod_aux; apply Zplus_le_0_compat; apply Zmult_le_0_compat; auto with zarith.
+ apply Zle_lt_trans with ([[z]]-0); auto with zarith.
+ unfold Zminus; apply Zplus_le_compat_l; apply Zle_left_rev; simpl; rewrite Zopp_involutive.
+ apply Zmult_le_0_compat; auto with zarith.
+ (** there is a carry in hh + ll **)
+ rewrite Zmult_1_l.
+ generalize (spec_w_compare xl xh); case (w_compare xl xh); intros Hxlh;
+ try rewrite Hxlh; try rewrite spec_w_1; try (ring; fail).
+ generalize (spec_w_compare yl yh); case (w_compare yl yh); intros Hylh;
+ try rewrite Hylh; try rewrite spec_w_1; try (ring; fail).
+ match goal with |- context[ww_sub_c ?x ?y] =>
+ generalize (spec_ww_sub_c x y); case (ww_sub_c x y); try rewrite spec_w_1;
+ intros z1 Hz2
+ end.
+ simpl in Hz2; rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ rewrite spec_w_0; rewrite Zmult_0_l; rewrite Zplus_0_l.
+ generalize Hz2; clear Hz2; unfold interp_carry.
+ repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ match goal with |- context[ww_add_c ?x ?y] =>
+ generalize (spec_ww_add_c x y); case (ww_add_c x y); try rewrite spec_w_1;
+ intros z1 Hz2
+ end.
+ simpl in Hz2; rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ rewrite spec_w_2; unfold interp_carry in Hz2.
+ apply trans_equal with (wwB + (1 * wwB + [[z1]])).
+ ring.
+ rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ generalize (spec_w_compare yl yh); case (w_compare yl yh); intros Hylh;
+ try rewrite Hylh; try rewrite spec_w_1; try (ring; fail).
+ match goal with |- context[ww_add_c ?x ?y] =>
+ generalize (spec_ww_add_c x y); case (ww_add_c x y); try rewrite spec_w_1;
+ intros z1 Hz2
+ end.
+ simpl in Hz2; rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ rewrite spec_w_2; unfold interp_carry in Hz2.
+ apply trans_equal with (wwB + (1 * wwB + [[z1]])).
+ ring.
+ rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ match goal with |- context[ww_sub_c ?x ?y] =>
+ generalize (spec_ww_sub_c x y); case (ww_sub_c x y); try rewrite spec_w_1;
+ intros z1 Hz2
+ end.
+ simpl in Hz2; rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ rewrite spec_w_0; rewrite Zmult_0_l; rewrite Zplus_0_l.
+ match goal with |- context[(?x - ?y) * (?z - ?t)] =>
+ replace ((x - y) * (z - t)) with ((y - x) * (t - z)); [idtac | ring]
+ end.
+ generalize Hz2; clear Hz2; unfold interp_carry.
+ repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
+ repeat rewrite Zmod_def_small; auto with zarith; try (ring; fail).
+ Qed.
+
+ Lemma sub_carry : forall xh xl yh yl z,
+ 0 <= z ->
+ [|xh|]*[|yl|] + [|xl|]*[|yh|] = wwB + z ->
+ z < wwB.
+ Proof.
+ intros xh xl yh yl z Hle Heq.
+ destruct (Z_le_gt_dec wwB z);auto with zarith.
+ generalize (Zmult_lt_b _ _ _ (spec_to_Z xh) (spec_to_Z yl)).
+ generalize (Zmult_lt_b _ _ _ (spec_to_Z xl) (spec_to_Z yh)).
+ rewrite <- wwB_wBwB;intros H1 H2.
+ assert (H3 := wB_pos w_digits).
+ assert (2*wB <= wwB).
+ rewrite wwB_wBwB; rewrite Zpower_2; apply Zmult_le_compat;zarith.
+ omega.
+ Qed.
+
+ Ltac Spec_ww_to_Z x :=
+ let H:= fresh "H" in
+ assert (H:= spec_ww_to_Z x).
+
+ Ltac Zmult_lt_b x y :=
+ let H := fresh "H" in
+ assert (H := Zmult_lt_b _ _ _ (spec_to_Z x) (spec_to_Z y)).
+
+ Lemma spec_ww_karatsuba_c : forall x y, [||ww_karatsuba_c x y||]=[[x]]*[[y]].
+ Proof.
+ intros x y; unfold ww_karatsuba_c;apply spec_gen_mul_c.
+ intros; apply spec_kara_prod; auto.
+ Qed.
+
+ Lemma spec_ww_mul : forall x y, [[ww_mul x y]] = [[x]]*[[y]] mod wwB.
+ Proof.
+ assert (U:= lt_0_wB w_digits).
+ assert (U1:= lt_0_wwB w_digits).
+ intros x y; case x; auto; intros xh xl.
+ case y; auto.
+ simpl; rewrite Zmult_0_r; rewrite Zmod_def_small; auto with zarith.
+ intros yh yl;simpl.
+ repeat (rewrite spec_ww_add || rewrite spec_w_W0 || rewrite spec_w_mul_c
+ || rewrite spec_w_add || rewrite spec_w_mul).
+ rewrite <- Zmod_plus; auto with zarith.
+ repeat (rewrite Zmult_plus_distr_l || rewrite Zmult_plus_distr_r).
+ rewrite <- Zmult_mod_distr_r; auto with zarith.
+ rewrite <- Zpower_2; rewrite <- wwB_wBwB; auto with zarith.
+ rewrite Zmod_plus; auto with zarith.
+ rewrite Zmod_mod; auto with zarith.
+ rewrite <- Zmod_plus; auto with zarith.
+ match goal with |- ?X mod _ = _ =>
+ rewrite <- Z_mod_plus with (a := X) (b := [|xh|] * [|yh|])
+ end; auto with zarith.
+ eq_tac; auto; rewrite wwB_wBwB; ring.
+ Qed.
+
+ Lemma spec_ww_square_c : forall x, [||ww_square_c x||] = [[x]]*[[x]].
+ Proof.
+ destruct x as [ |xh xl];simpl;trivial.
+ case_eq match ww_add_c (w_mul_c xh xl) (w_mul_c xh xl) with
+ | C0 cc => (w_0, cc)
+ | C1 cc => (w_1, cc)
+ end;intros wc cc Heq.
+ apply (spec_mul_aux xh xl xh xl wc cc);trivial.
+ generalize Heq (spec_ww_add_c (w_mul_c xh xl) (w_mul_c xh xl));clear Heq.
+ rewrite spec_w_mul_c;destruct (ww_add_c (w_mul_c xh xl) (w_mul_c xh xl));
+ unfold interp_carry;try rewrite Zmult_1_l;intros Heq Heq';inversion Heq;
+ rewrite (Zmult_comm [|xl|]);subst.
+ rewrite spec_w_0;rewrite Zmult_0_l;rewrite Zplus_0_l;trivial.
+ rewrite spec_w_1;rewrite Zmult_1_l;rewrite <- wwB_wBwB;trivial.
+ Qed.
+
+ Section GenMulAddn1Proof.
+
+ Variable w_mul_add : w -> w -> w -> w * w.
+ Variable spec_w_mul_add : forall x y r,
+ let (h,l):= w_mul_add x y r in
+ [|h|]*wB+[|l|] = [|x|]*[|y|] + [|r|].
+
+ Lemma spec_gen_mul_add_n1 : forall n x y r,
+ let (h,l) := gen_mul_add_n1 w_mul_add n x y r in
+ [|h|]*gen_wB w_digits n + [!n|l!] = [!n|x!]*[|y|]+[|r|].
+ Proof.
+ induction n;intros x y r;trivial.
+ exact (spec_w_mul_add x y r).
+ unfold gen_mul_add_n1;destruct x as[ |xh xl];
+ fold(gen_mul_add_n1 w_mul_add).
+ rewrite spec_w_0;rewrite spec_extend;simpl;trivial.
+ assert(H:=IHn xl y r);destruct (gen_mul_add_n1 w_mul_add n xl y r)as(rl,l).
+ assert(U:=IHn xh y rl);destruct(gen_mul_add_n1 w_mul_add n xh y rl)as(rh,h).
+ rewrite <- gen_wB_wwB. rewrite spec_gen_WW;simpl;trivial.
+ rewrite Zmult_plus_distr_l;rewrite <- Zplus_assoc;rewrite <- H.
+ rewrite Zmult_assoc;rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ rewrite U;ring.
+ Qed.
+
+ End GenMulAddn1Proof.
+
+ Lemma spec_w_mul_add : forall x y r,
+ let (h,l):= w_mul_add x y r in
+ [|h|]*wB+[|l|] = [|x|]*[|y|] + [|r|].
+ Proof.
+ intros x y r;unfold w_mul_add;assert (H:=spec_w_mul_c x y);
+ destruct (w_mul_c x y) as [ |h l];simpl;rewrite <- H.
+ rewrite spec_w_0;trivial.
+ assert (U:=spec_w_add_c l r);destruct (w_add_c l r) as [lr|lr];unfold
+ interp_carry in U;try rewrite Zmult_1_l in H;simpl.
+ rewrite U;ring. rewrite spec_w_succ. rewrite Zmod_def_small.
+ rewrite <- Zplus_assoc;rewrite <- U;ring.
+ simpl in H;assert (H1:= Zmult_lt_b _ _ _ (spec_to_Z x) (spec_to_Z y)).
+ rewrite <- H in H1.
+ assert (H2:=spec_to_Z h);split;zarith.
+ case H1;clear H1;intro H1;clear H1.
+ replace (wB ^ 2 - 2 * wB) with ((wB - 2)*wB). 2:ring.
+ intros H0;assert (U1:= wB_pos w_digits).
+ assert (H1 := beta_lex _ _ _ _ _ H0 (spec_to_Z l));zarith.
+ Qed.
+
+(* End GenProof. *)
+
+End GenMul.
diff --git a/theories/Ints/num/GenSqrt.v b/theories/Ints/num/GenSqrt.v
new file mode 100644
index 0000000000..074f7eb537
--- /dev/null
+++ b/theories/Ints/num/GenSqrt.v
@@ -0,0 +1,1312 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section GenSqrt.
+ Variable w : Set.
+ Variable w_is_even : w -> bool.
+ Variable w_compare : w -> w -> comparison.
+ Variable w_0 : w.
+ Variable w_1 : w.
+ Variable w_Bm1 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable w_W0 : w -> zn2z w.
+ Variable w_0W : w -> zn2z w.
+ Variable w_sub : w -> w -> w.
+ Variable w_sub_c : w -> w -> carry w.
+ Variable w_square_c : w -> zn2z w.
+ Variable w_div21 : w -> w -> w -> w * w.
+ Variable w_add_mul_div : positive -> w -> w -> w.
+ Variable w_digits : positive.
+ Variable w_add_c : w -> w -> carry w.
+ Variable w_sqrt2 : w -> w -> w * carry w.
+ Variable ww_pred_c : zn2z w -> carry (zn2z w).
+ Variable ww_pred : zn2z w -> zn2z w.
+ Variable ww_add_c : zn2z w -> zn2z w -> carry (zn2z w).
+ Variable ww_add : zn2z w -> zn2z w -> zn2z w.
+ Variable ww_sub_c : zn2z w -> zn2z w -> carry (zn2z w).
+ Variable ww_add_mul_div : positive -> zn2z w -> zn2z w -> zn2z w.
+ Variable ww_head0 : zn2z w -> N.
+ Variable ww_compare : zn2z w -> zn2z w -> comparison.
+
+ Let wwBm1 := ww_Bm1 w_Bm1.
+
+ Definition ww_is_even x :=
+ match x with
+ | W0 => true
+ | WW xh xl => w_is_even xl
+ end.
+
+ Let w_div21c x y z :=
+ match w_compare x z with
+ | Eq =>
+ match w_compare y z with
+ Eq => (C1 w_1, w_0)
+ | Gt => (C1 w_1, w_sub y z)
+ | Lt => (C1 w_0, y)
+ end
+ | Gt =>
+ let x1 := w_sub x z in
+ let (q, r) := w_div21 x1 y z in
+ (C1 q, r)
+ | Lt =>
+ let (q, r) := w_div21 x y z in
+ (C0 q, r)
+ end.
+
+ Let w_div2s x y s :=
+ match x with
+ C1 x1 =>
+ let x2 := w_sub x1 s in
+ let (q, r) := w_div21c x2 y s in
+ match q with
+ C0 q1 =>
+ if w_is_even q1 then
+ (C0 (w_add_mul_div (w_digits - 1) w_1 q1), C0 r)
+ else
+ (C0 (w_add_mul_div (w_digits - 1) w_1 q1), w_add_c r s)
+ | C1 q1 =>
+ if w_is_even q1 then
+ (C1 (w_add_mul_div (w_digits - 1) w_0 q1), C0 r)
+ else
+ (C1 (w_add_mul_div (w_digits - 1) w_0 q1), w_add_c r s)
+ end
+ | C0 x1 =>
+ let (q, r) := w_div21c x1 y s in
+ match q with
+ C0 q1 =>
+ if w_is_even q1 then
+ (C0 (w_add_mul_div (w_digits - 1) w_0 q1), C0 r)
+ else
+ (C0 (w_add_mul_div (w_digits - 1) w_0 q1), w_add_c r s)
+ | C1 q1 =>
+ if w_is_even q1 then
+ (C0 (w_add_mul_div (w_digits - 1) w_1 q1), C0 r)
+ else
+ (C0 (w_add_mul_div (w_digits - 1) w_1 q1), w_add_c r s)
+ end
+ end.
+
+ Definition split x :=
+ match x with
+ | W0 => (w_0,w_0)
+ | WW h l => (h,l)
+ end.
+
+ Definition ww_sqrt2 x y :=
+ let (x1, x2) := split x in
+ let (y1, y2) := split y in
+ let ( q, r) := w_sqrt2 x1 x2 in
+ let (q1, r1) := w_div2s r y1 q in
+ match q1 with
+ C0 q1 =>
+ let q2 := w_square_c q1 in
+ let a := WW q q1 in
+ match r1 with
+ C1 r2 =>
+ match ww_sub_c (WW r2 y2) q2 with
+ C0 r3 => (a, C1 r3)
+ | C1 r3 => (a, C0 r3)
+ end
+ | C0 r2 =>
+ match ww_sub_c (WW r2 y2) q2 with
+ C0 r3 => (a, C0 r3)
+ | C1 r3 =>
+ let a2 := ww_add_mul_div 1 a W0 in
+ match ww_pred_c a2 with
+ C0 a3 =>
+ (ww_pred a, ww_add_c a3 r3)
+ | C1 a3 =>
+ (ww_pred a, C0 (ww_add a3 r3))
+ end
+ end
+ end
+ | C1 q1 =>
+ let a1 := WW q w_Bm1 in
+ let a2 := ww_add_mul_div 1 a1 wwBm1 in
+ (a1, ww_add_c a2 y)
+ end.
+
+ Definition ww_is_zero x :=
+ match ww_compare W0 x with
+ Eq => true
+ | _ => false
+ end.
+
+ Definition ww_head1 x :=
+ match ww_head0 x with
+ N0 => N0
+ | Npos xH => N0
+ | Npos (xO _) as U => U
+ | Npos (xI V) => Npos (xO V)
+ end.
+
+ Definition ww_sqrt x :=
+ if (ww_is_zero x) then W0
+ else
+ match (ww_head1 x) with
+ N0 =>
+ match x with
+ W0 => W0
+ | WW x1 x2 => WW w_0 (fst (w_sqrt2 x1 x2))
+ end
+ | Npos p =>
+ match ww_add_mul_div p x W0 with
+ W0 => W0
+ | WW x1 x2 =>
+ let (r, _) := w_sqrt2 x1 x2 in
+ WW w_0 (w_add_mul_div (w_digits - (Pdiv2 p)) w_0 r)
+ end
+ end.
+
+
+ Variable w_to_Z : w -> Z.
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[+| c |]" :=
+ (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Notation "[+[ c ]]" :=
+ (interp_carry 1 wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+
+ Notation "[|| x ||]" :=
+ (zn2z_to_Z wwB (ww_to_Z w_digits w_to_Z) x) (at level 0, x at level 99).
+
+ Notation "[! n | x !]" := (gen_to_Z w_digits w_to_Z n x)
+ (at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_1 : [|w_1|] = 1.
+ Variable spec_w_Bm1 : [|w_Bm1|] = wB - 1.
+
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+ Variable spec_w_W0 : forall h, [[w_W0 h]] = [|h|] * wB.
+ Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
+ Variable spec_w_is_even : forall x,
+ if w_is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1.
+ Variable spec_w_compare : forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Variable spec_w_sub : forall x y, [|w_sub x y|] = ([|x|] - [|y|]) mod wB.
+ Variable spec_w_square_c : forall x, [[ w_square_c x]] = [|x|] * [|x|].
+ Variable spec_w_div21 : forall a1 a2 b,
+ wB/2 <= [|b|] ->
+ [|a1|] < [|b|] ->
+ let (q,r) := w_div21 a1 a2 b in
+ [|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+ Variable spec_w_add_mul_div : forall x y p,
+ Zpos p < Zpos w_digits ->
+ [| w_add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos w_digits) - (Zpos p)))) mod wB.
+ Variable spec_ww_add_mul_div : forall x y p,
+ Zpos p < Zpos (xO w_digits) ->
+ [[ ww_add_mul_div p x y ]] =
+ ([[x]] * (2^ Zpos p) +
+ [[y]] / (2^ (Zpos (xO w_digits) - Zpos p))) mod wwB.
+ Variable spec_w_add_c : forall x y, [+|w_add_c x y|] = [|x|] + [|y|].
+ Variable spec_ww_add : forall x y, [[ww_add x y]] = ([[x]] + [[y]]) mod wwB.
+ Variable spec_w_sqrt2 : forall x y,
+ wB/ 4 <= [|x|] ->
+ let (s,r) := w_sqrt2 x y in
+ [[WW x y]] = [|s|] ^ 2 + [+|r|] /\
+ [+|r|] <= 2 * [|s|].
+ Variable spec_ww_sub_c : forall x y, [-[ww_sub_c x y]] = [[x]] - [[y]].
+ Variable spec_ww_pred_c : forall x, [-[ww_pred_c x]] = [[x]] - 1.
+ Variable spec_ww_pred : forall x, [[ww_pred x]] = ([[x]] - 1) mod wwB.
+ Variable spec_ww_add_c : forall x y, [+[ww_add_c x y]] = [[x]] + [[y]].
+ Variable spec_ww_compare : forall x y,
+ match ww_compare x y with
+ | Eq => [[x]] = [[y]]
+ | Lt => [[x]] < [[y]]
+ | Gt => [[x]] > [[y]]
+ end.
+ Variable spec_ww_head0 : forall x, 0 < [[x]] ->
+ wwB/ 2 <= 2 ^ (Z_of_N (ww_head0 x)) * [[x]] < wwB.
+
+ Let spec_ww_Bm1 : [[wwBm1]] = wwB - 1.
+ Proof. refine (spec_ww_Bm1 w_Bm1 w_digits w_to_Z _);auto. Qed.
+
+
+ Hint Rewrite spec_w_0 spec_w_1 w_Bm1 spec_w_WW spec_w_sub
+ spec_w_div21 spec_w_add_mul_div spec_ww_Bm1
+ spec_w_add_c spec_w_sqrt2: w_rewrite.
+
+ Lemma spec_ww_is_even : forall x,
+ if ww_is_even x then [[x]] mod 2 = 0 else [[x]] mod 2 = 1.
+ intros x; case x; simpl ww_is_even.
+ simpl.
+ rewrite Zmod_def_small; auto with zarith.
+ intros w1 w2; simpl.
+ unfold base.
+ rewrite Zmod_plus; auto with zarith.
+ rewrite (fun x y => (Zdivide_mod (x * y))); auto with zarith.
+ rewrite Zplus_0_l; rewrite Zmod_mod; auto with zarith.
+ apply spec_w_is_even; auto with zarith.
+ apply Zdivide_mult_r; apply Zpower_divide; auto with zarith.
+ red; simpl; auto.
+ Qed.
+
+ Theorem spec_w_div21c : forall a1 a2 b,
+ wB/2 <= [|b|] ->
+ let (q,r) := w_div21c a1 a2 b in
+ [|a1|] * wB + [|a2|] = [+|q|] * [|b|] + [|r|] /\ 0 <= [|r|] < [|b|].
+ intros a1 a2 b Hb; unfold w_div21c.
+ assert (H: 0 < [|b|]); auto with zarith.
+ assert (U := wB_pos w_digits).
+ apply Zlt_le_trans with (2 := Hb); auto with zarith.
+ apply Zlt_le_trans with 1; auto with zarith.
+ apply Zdiv_le_lower_bound; auto with zarith.
+ repeat match goal with |- context[w_compare ?y ?z] =>
+ generalize (spec_w_compare y z);
+ case (w_compare y z)
+ end.
+ intros H1 H2; split.
+ unfold interp_carry; autorewrite with w_rewrite rm10; auto with zarith.
+ rewrite H1; rewrite H2; ring.
+ autorewrite with w_rewrite; auto with zarith.
+ intros H1 H2; split.
+ unfold interp_carry; autorewrite with w_rewrite rm10; auto with zarith.
+ rewrite H2; ring.
+ destruct (spec_to_Z a2);auto with zarith.
+ intros H1 H2; split.
+ unfold interp_carry; autorewrite with w_rewrite rm10; auto with zarith.
+ rewrite H2; rewrite Zmod_def_small; auto with zarith.
+ ring.
+ destruct (spec_to_Z a2);auto with zarith.
+ rewrite spec_w_sub; auto with zarith.
+ destruct (spec_to_Z a2) as [H3 H4];auto with zarith.
+ rewrite Zmod_def_small; auto with zarith.
+ split; auto with zarith.
+ assert ([|a2|] < 2 * [|b|]); auto with zarith.
+ apply Zlt_le_trans with (2 * (wB / 2)); auto with zarith.
+ rewrite wB_div_2; auto.
+ intros H1.
+ match goal with |- context[w_div21 ?y ?z ?t] =>
+ generalize (@spec_w_div21 y z t Hb H1);
+ case (w_div21 y z t); simpl; autorewrite with w_rewrite;
+ auto
+ end.
+ intros H1.
+ assert (H2: [|w_sub a1 b|] < [|b|]).
+ rewrite spec_w_sub; auto with zarith.
+ rewrite Zmod_def_small; auto with zarith.
+ assert ([|a1|] < 2 * [|b|]); auto with zarith.
+ apply Zlt_le_trans with (2 * (wB / 2)); auto with zarith.
+ rewrite wB_div_2; auto.
+ destruct (spec_to_Z a1);auto with zarith.
+ destruct (spec_to_Z a1);auto with zarith.
+ match goal with |- context[w_div21 ?y ?z ?t] =>
+ generalize (@spec_w_div21 y z t Hb H2);
+ case (w_div21 y z t); autorewrite with w_rewrite;
+ auto
+ end.
+ intros w0 w1; replace [+|C1 w0|] with (wB + [|w0|]).
+ rewrite Zmod_def_small; auto with zarith.
+ intros (H3, H4); split; auto.
+ rewrite Zmult_plus_distr_l.
+ rewrite <- Zplus_assoc; rewrite <- H3; ring.
+ split; auto with zarith.
+ assert ([|a1|] < 2 * [|b|]); auto with zarith.
+ apply Zlt_le_trans with (2 * (wB / 2)); auto with zarith.
+ rewrite wB_div_2; auto.
+ destruct (spec_to_Z a1);auto with zarith.
+ destruct (spec_to_Z a1);auto with zarith.
+ simpl; case wB; auto.
+ Qed.
+
+ Theorem C0_id: forall p, [+|C0 p|] = [|p|].
+ intros p; simpl; auto.
+ Qed.
+
+ Hypothesis more_than_one_bit: 1 < Zpos w_digits.
+
+ Theorem add_mult_div_2: forall w,
+ [|w_add_mul_div (w_digits - 1) w_0 w|] = [|w|] / 2.
+ intros w1.
+ rewrite spec_w_add_mul_div; auto with zarith.
+ autorewrite with w_rewrite rm10.
+ match goal with |- context[?X - ?Y] =>
+ replace (X - Y) with 1
+ end.
+ rewrite Zpower_exp_1; rewrite Zmod_def_small; auto with zarith.
+ destruct (spec_to_Z w1) as [H1 H2];auto with zarith.
+ split; auto with zarith.
+ apply Zdiv_lt_upper_bound; auto with zarith.
+ rewrite Zpos_minus; auto with zarith.
+ rewrite Zpos_minus; auto with zarith.
+ Qed.
+
+ Theorem add_mult_div_2_plus_1: forall w,
+ [|w_add_mul_div (w_digits - 1) w_1 w|] =
+ [|w|] / 2 + 2 ^ Zpos (w_digits - 1).
+ intros w1.
+ autorewrite with w_rewrite rm10; auto with zarith.
+ match goal with |- context[?X - ?Y] =>
+ replace (X - Y) with 1
+ end.
+ rewrite Zpower_exp_1; rewrite Zmod_def_small; auto with zarith.
+ destruct (spec_to_Z w1) as [H1 H2];auto with zarith.
+ split; auto with zarith.
+ unfold base.
+ match goal with |- _ < _ ^ ?X =>
+ assert (tmp: forall p, 1 + (p - 1) = p); auto with zarith;
+ rewrite <- (tmp X); clear tmp
+ end.
+ rewrite Zpower_exp; try rewrite Zpower_exp_1; auto with zarith.
+ rewrite Zpos_minus; auto with zarith.
+ match goal with |- ?X + ?Y < _ =>
+ assert (Y < X); auto with zarith
+ end.
+ apply Zdiv_lt_upper_bound; auto with zarith.
+ pattern 2 at 2; rewrite <- Zpower_exp_1; rewrite <- Zpower_exp;
+ auto with zarith.
+ assert (tmp: forall p, (p - 1) + 1 = p); auto with zarith;
+ rewrite tmp; clear tmp; auto with zarith.
+ rewrite Zpos_minus; auto with zarith.
+ rewrite Zpos_minus; auto with zarith.
+ Qed.
+
+ Theorem add_mult_mult_2: forall w,
+ [|w_add_mul_div 1 w w_0|] = 2 * [|w|] mod wB.
+ intros w1.
+ autorewrite with w_rewrite rm10; auto with zarith.
+ rewrite Zpower_exp_1; auto with zarith.
+ rewrite Zmult_comm; auto.
+ Qed.
+
+ Theorem ww_add_mult_mult_2: forall w,
+ [[ww_add_mul_div 1 w W0]] = 2 * [[w]] mod wwB.
+ intros w1.
+ rewrite spec_ww_add_mul_div; auto with zarith.
+ autorewrite with w_rewrite rm10.
+ rewrite Zpower_exp_1; auto with zarith.
+ rewrite Zmult_comm; auto.
+ Qed.
+
+ Theorem ww_add_mult_mult_2_plus_1: forall w,
+ [[ww_add_mul_div 1 w wwBm1]] =
+ (2 * [[w]] + 1) mod wwB.
+ intros w1.
+ rewrite spec_ww_add_mul_div; auto with zarith.
+ rewrite Zpower_exp_1; auto with zarith.
+ eq_tac; auto.
+ rewrite Zmult_comm; eq_tac; auto.
+ autorewrite with w_rewrite rm10.
+ unfold ww_digits, base.
+ apply sym_equal; apply Zdiv_unique with (r := 2 ^ (Zpos (ww_digits w_digits) - 1) -1);
+ auto with zarith.
+ apply Zpower_lt_0; auto with zarith.
+ match goal with |- 0 <= ?X - 1 =>
+ assert (0 < X); auto with zarith; red; reflexivity
+ end.
+ unfold ww_digits; split; auto with zarith.
+ match goal with |- 0 <= ?X - 1 =>
+ assert (0 < X); auto with zarith
+ end.
+ apply Zpower_lt_0; auto with zarith.
+ match goal with |- 0 <= ?X - 1 =>
+ assert (0 < X); auto with zarith; red; reflexivity
+ end.
+ unfold ww_digits; autorewrite with rm10.
+ assert (tmp: forall p q r, p + (q - r) = p + q - r); auto with zarith;
+ rewrite tmp; clear tmp.
+ assert (tmp: forall p, p + p = 2 * p); auto with zarith;
+ rewrite tmp; clear tmp.
+ eq_tac; auto.
+ pattern 2 at 2; rewrite <- Zpower_exp_1; rewrite <- Zpower_exp;
+ auto with zarith.
+ assert (tmp: forall p, 1 + (p - 1) = p); auto with zarith;
+ rewrite tmp; clear tmp; auto.
+ match goal with |- ?X - 1 >= 0 =>
+ assert (0 < X); auto with zarith; red; reflexivity
+ end.
+ Qed.
+
+ Theorem Zmod_plus_one: forall a1 b1, 0 < b1 -> (a1 + b1) mod b1 = a1 mod b1.
+ intros a1 b1 H; rewrite Zmod_plus; auto with zarith.
+ rewrite Z_mod_same; try rewrite Zplus_0_r; auto with zarith.
+ apply Zmod_mod; auto.
+ Qed.
+
+ Lemma C1_plus_wB: forall x, [+|C1 x|] = wB + [|x|].
+ unfold interp_carry; auto with zarith.
+ Qed.
+
+ Theorem spec_w_div2s : forall a1 a2 b,
+ wB/2 <= [|b|] -> [+|a1|] <= 2 * [|b|] ->
+ let (q,r) := w_div2s a1 a2 b in
+ [+|a1|] * wB + [|a2|] = [+|q|] * (2 * [|b|]) + [+|r|] /\ 0 <= [+|r|] < 2 * [|b|].
+ intros a1 a2 b H.
+ assert (HH: 0 < [|b|]); auto with zarith.
+ assert (U := wB_pos w_digits).
+ apply Zlt_le_trans with (2 := H); auto with zarith.
+ apply Zlt_le_trans with 1; auto with zarith.
+ apply Zdiv_le_lower_bound; auto with zarith.
+ unfold w_div2s; case a1; intros w0 H0.
+ match goal with |- context[w_div21c ?y ?z ?t] =>
+ generalize (@spec_w_div21c y z t H);
+ case (w_div21c y z t); autorewrite with w_rewrite;
+ auto
+ end.
+ intros c w1; case c.
+ simpl interp_carry; intros w2 (Hw1, Hw2).
+ match goal with |- context[w_is_even ?y] =>
+ generalize (spec_w_is_even y);
+ case (w_is_even y)
+ end.
+ repeat rewrite C0_id.
+ rewrite add_mult_div_2.
+ intros H1; split; auto with zarith.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1; ring.
+ repeat rewrite C0_id.
+ rewrite add_mult_div_2.
+ rewrite spec_w_add_c; auto with zarith.
+ intros H1; split; auto with zarith.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1; ring.
+ intros w2; rewrite C1_plus_wB.
+ intros (Hw1, Hw2).
+ match goal with |- context[w_is_even ?y] =>
+ generalize (spec_w_is_even y);
+ case (w_is_even y)
+ end.
+ repeat rewrite C0_id.
+ intros H1; split; auto with zarith.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1.
+ repeat rewrite C0_id.
+ rewrite add_mult_div_2_plus_1; unfold base.
+ match goal with |- context[_ ^ ?X] =>
+ assert (tmp: forall p, 1 + (p - 1) = p); auto with zarith;
+ rewrite <- (tmp X); clear tmp; rewrite Zpower_exp;
+ try rewrite Zpower_exp_1; auto with zarith
+ end.
+ rewrite Zpos_minus; auto with zarith.
+ ring.
+ repeat rewrite C0_id.
+ rewrite spec_w_add_c; auto with zarith.
+ intros H1; split; auto with zarith.
+ rewrite add_mult_div_2_plus_1.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1.
+ unfold base.
+ match goal with |- context[_ ^ ?X] =>
+ assert (tmp: forall p, 1 + (p - 1) = p); auto with zarith;
+ rewrite <- (tmp X); clear tmp; rewrite Zpower_exp;
+ try rewrite Zpower_exp_1; auto with zarith
+ end.
+ rewrite Zpos_minus; auto with zarith.
+ ring.
+ repeat rewrite C1_plus_wB in H0.
+ rewrite C1_plus_wB.
+ match goal with |- context[w_div21c ?y ?z ?t] =>
+ generalize (@spec_w_div21c y z t H);
+ case (w_div21c y z t); autorewrite with w_rewrite;
+ auto
+ end.
+ intros c w1; case c.
+ intros w2 (Hw1, Hw2); rewrite C0_id in Hw1.
+ rewrite <- Zmod_plus_one in Hw1; auto with zarith.
+ rewrite Zmod_def_small in Hw1; auto with zarith.
+ match goal with |- context[w_is_even ?y] =>
+ generalize (spec_w_is_even y);
+ case (w_is_even y)
+ end.
+ repeat rewrite C0_id.
+ intros H1; split; auto with zarith.
+ rewrite add_mult_div_2_plus_1.
+ replace (wB + [|w0|]) with ([|b|] + ([|w0|] - [|b|] + wB));
+ auto with zarith.
+ rewrite Zmult_plus_distr_l; rewrite <- Zplus_assoc.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1; unfold base.
+ match goal with |- context[_ ^ ?X] =>
+ assert (tmp: forall p, 1 + (p - 1) = p); auto with zarith;
+ rewrite <- (tmp X); clear tmp; rewrite Zpower_exp;
+ try rewrite Zpower_exp_1; auto with zarith
+ end.
+ rewrite Zpos_minus; auto with zarith.
+ ring.
+ repeat rewrite C0_id.
+ rewrite add_mult_div_2_plus_1.
+ rewrite spec_w_add_c; auto with zarith.
+ intros H1; split; auto with zarith.
+ replace (wB + [|w0|]) with ([|b|] + ([|w0|] - [|b|] + wB));
+ auto with zarith.
+ rewrite Zmult_plus_distr_l; rewrite <- Zplus_assoc.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1; unfold base.
+ match goal with |- context[_ ^ ?X] =>
+ assert (tmp: forall p, 1 + (p - 1) = p); auto with zarith;
+ rewrite <- (tmp X); clear tmp; rewrite Zpower_exp;
+ try rewrite Zpower_exp_1; auto with zarith
+ end.
+ rewrite Zpos_minus; auto with zarith.
+ ring.
+ split; auto with zarith.
+ destruct (spec_to_Z b);auto with zarith.
+ destruct (spec_to_Z w0);auto with zarith.
+ destruct (spec_to_Z b);auto with zarith.
+ destruct (spec_to_Z b);auto with zarith.
+ intros w2; rewrite C1_plus_wB.
+ rewrite <- Zmod_plus_one; auto with zarith.
+ rewrite Zmod_def_small; auto with zarith.
+ intros (Hw1, Hw2).
+ match goal with |- context[w_is_even ?y] =>
+ generalize (spec_w_is_even y);
+ case (w_is_even y)
+ end.
+ repeat (rewrite C0_id || rewrite C1_plus_wB).
+ intros H1; split; auto with zarith.
+ rewrite add_mult_div_2.
+ replace (wB + [|w0|]) with ([|b|] + ([|w0|] - [|b|] + wB));
+ auto with zarith.
+ rewrite Zmult_plus_distr_l; rewrite <- Zplus_assoc.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1; ring.
+ repeat (rewrite C0_id || rewrite C1_plus_wB).
+ rewrite spec_w_add_c; auto with zarith.
+ intros H1; split; auto with zarith.
+ rewrite add_mult_div_2.
+ replace (wB + [|w0|]) with ([|b|] + ([|w0|] - [|b|] + wB));
+ auto with zarith.
+ rewrite Zmult_plus_distr_l; rewrite <- Zplus_assoc.
+ rewrite Hw1.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] 2);
+ auto with zarith.
+ rewrite H1; ring.
+ split; auto with zarith.
+ destruct (spec_to_Z b);auto with zarith.
+ destruct (spec_to_Z w0);auto with zarith.
+ destruct (spec_to_Z b);auto with zarith.
+ destruct (spec_to_Z b);auto with zarith.
+ Qed.
+
+ Theorem wB_div_4: 4 * (wB / 4) = wB.
+ Proof.
+ unfold base.
+ assert (2 ^ Zpos w_digits =
+ 4 * (2 ^ (Zpos w_digits - 2))).
+ change 4 with (2 ^ 2).
+ rewrite <- Zpower_exp; auto with zarith.
+ eq_tac; auto with zarith.
+ rewrite H.
+ rewrite (fun x => (Zmult_comm 4 (2 ^x))).
+ rewrite Z_div_mult; auto with zarith.
+ Qed.
+
+ Theorem Zsquare_mult: forall p, p ^ 2 = p * p.
+ intros p; change 2 with (1 + 1); rewrite Zpower_exp;
+ try rewrite Zpower_exp_1; auto with zarith.
+ Qed.
+
+ Theorem Zsquare_pos: forall p, 0 <= p ^ 2.
+ intros p; case (Zle_or_lt 0 p); intros H1.
+ rewrite Zsquare_mult; apply Zmult_le_0_compat; auto with zarith.
+ rewrite Zsquare_mult; replace (p * p) with ((- p) * (- p)); try ring.
+ apply Zmult_le_0_compat; auto with zarith.
+ Qed.
+
+ Lemma spec_split: forall x,
+ [|fst (split x)|] * wB + [|snd (split x)|] = [[x]].
+ intros x; case x; simpl; autorewrite with w_rewrite;
+ auto with zarith.
+ Qed.
+
+ Theorem mult_wwB: forall x y, [|x|] * [|y|] < wwB.
+ Proof.
+ intros x y; rewrite wwB_wBwB; rewrite Zpower_2.
+ generalize (spec_to_Z x); intros U.
+ generalize (spec_to_Z y); intros U1.
+ apply Zle_lt_trans with ((wB -1 ) * (wB - 1)); auto with zarith.
+ apply Zmult_le_compat; auto with zarith.
+ repeat (rewrite Zmult_minus_distr_r || rewrite Zmult_minus_distr_l);
+ auto with zarith.
+ Qed.
+ Hint Resolve mult_wwB.
+
+ Lemma spec_ww_sqrt2 : forall x y,
+ wwB/ 4 <= [[x]] ->
+ let (s,r) := ww_sqrt2 x y in
+ [||WW x y||] = [[s]] ^ 2 + [+[r]] /\
+ [+[r]] <= 2 * [[s]].
+ intros x y H; unfold ww_sqrt2.
+ repeat match goal with |- context[split ?x] =>
+ generalize (spec_split x); case (split x)
+ end; simpl fst; simpl snd.
+ intros w0 w1 Hw0 w2 w3 Hw1.
+ assert (U: wB/4 <= [|w2|]).
+ case (Zle_or_lt (wB / 4) [|w2|]); auto; intros H1.
+ contradict H; apply Zlt_not_le.
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ pattern wB at 1; rewrite <- wB_div_4; rewrite <- Zmult_assoc;
+ rewrite Zmult_comm.
+ rewrite Z_div_mult; auto with zarith.
+ rewrite <- Hw1.
+ match goal with |- _ < ?X =>
+ pattern X; rewrite <- Zplus_0_r; apply beta_lex_inv;
+ auto with zarith
+ end.
+ destruct (spec_to_Z w3);auto with zarith.
+ generalize (@spec_w_sqrt2 w2 w3 U); case (w_sqrt2 w2 w3).
+ intros w4 c (H1, H2).
+ assert (U1: wB/2 <= [|w4|]).
+ case (Zle_or_lt (wB/2) [|w4|]); auto with zarith.
+ intros U1.
+ assert (U2 : [|w4|] <= wB/2 -1); auto with zarith.
+ assert (U3 : [|w4|] ^ 2 <= wB/4 * wB - wB + 1); auto with zarith.
+ match goal with |- ?X ^ 2 <= ?Y =>
+ rewrite Zsquare_mult;
+ replace Y with ((wB/2 - 1) * (wB/2 -1))
+ end.
+ apply Zmult_le_compat; auto with zarith.
+ destruct (spec_to_Z w4);auto with zarith.
+ destruct (spec_to_Z w4);auto with zarith.
+ pattern wB at 4 5; rewrite <- wB_div_2.
+ rewrite Zmult_assoc.
+ replace ((wB / 4) * 2) with (wB / 2).
+ ring.
+ pattern wB at 1; rewrite <- wB_div_4.
+ change 4 with (2 * 2).
+ rewrite <- Zmult_assoc; rewrite (Zmult_comm 2).
+ rewrite Z_div_mult; try ring; auto with zarith.
+ assert (U4 : [+|c|] <= wB -2); auto with zarith.
+ apply Zle_trans with (1 := H2).
+ match goal with |- ?X <= ?Y =>
+ replace Y with (2 * (wB/ 2 - 1)); auto with zarith
+ end.
+ pattern wB at 2; rewrite <- wB_div_2; auto with zarith.
+ match type of H1 with ?X = _ =>
+ assert (U5: X < wB / 4 * wB)
+ end.
+ rewrite H1; auto with zarith.
+ contradict U; apply Zlt_not_le.
+ apply Zmult_lt_reg_r with wB; auto with zarith.
+ destruct (spec_to_Z w4);auto with zarith.
+ apply Zle_lt_trans with (2 := U5).
+ unfold ww_to_Z, zn2z_to_Z.
+ destruct (spec_to_Z w3);auto with zarith.
+ generalize (@spec_w_div2s c w0 w4 U1 H2).
+ case (w_div2s c w0 w4).
+ intros c0; case c0; intros w5;
+ repeat (rewrite C0_id || rewrite C1_plus_wB).
+ intros c1; case c1; intros w6;
+ repeat (rewrite C0_id || rewrite C1_plus_wB).
+ intros (H3, H4).
+ match goal with |- context [ww_sub_c ?y ?z] =>
+ generalize (spec_ww_sub_c y z); case (ww_sub_c y z)
+ end.
+ intros z; change [-[C0 z]] with ([[z]]).
+ change [+[C0 z]] with ([[z]]).
+ intros H5; rewrite spec_w_square_c in H5;
+ auto.
+ split.
+ unfold zn2z_to_Z; rewrite <- Hw1.
+ unfold ww_to_Z, zn2z_to_Z in H1; rewrite H1.
+ rewrite <- Hw0.
+ match goal with |- (?X ^2 + ?Y) * wwB + (?Z * wB + ?T) = ?U =>
+ apply trans_equal with ((X * wB) ^ 2 + (Y * wB + Z) * wB + T)
+ end.
+ repeat rewrite Zsquare_mult.
+ rewrite wwB_wBwB; ring.
+ rewrite H3.
+ rewrite H5.
+ unfold ww_to_Z, zn2z_to_Z.
+ repeat rewrite Zsquare_mult; ring.
+ rewrite H5.
+ unfold ww_to_Z, zn2z_to_Z.
+ match goal with |- ?X - ?Y * ?Y <= _ =>
+ assert (V := Zsquare_pos Y);
+ rewrite Zsquare_mult in V;
+ apply Zle_trans with X; auto with zarith;
+ clear V
+ end.
+ match goal with |- ?X * wB + ?Y <= 2 * (?Z * wB + ?T) =>
+ apply Zle_trans with ((2 * Z - 1) * wB + wB); auto with zarith
+ end.
+ destruct (spec_to_Z w1);auto with zarith.
+ match goal with |- ?X <= _ =>
+ replace X with (2 * [|w4|] * wB); auto with zarith
+ end.
+ rewrite Zmult_plus_distr_r; rewrite Zmult_assoc.
+ destruct (spec_to_Z w5); auto with zarith.
+ ring.
+ intros z; replace [-[C1 z]] with (- wwB + [[z]]).
+ 2: simpl; case wwB; auto with zarith.
+ intros H5; rewrite spec_w_square_c in H5;
+ auto.
+ match goal with |- context [ww_pred_c ?y] =>
+ generalize (spec_ww_pred_c y); case (ww_pred_c y)
+ end.
+ intros z1; change [-[C0 z1]] with ([[z1]]).
+ rewrite ww_add_mult_mult_2.
+ rewrite spec_ww_add_c.
+ rewrite spec_ww_pred.
+ rewrite <- Zmod_unique with (q := 1) (r := -wwB + 2 * [[WW w4 w5]]);
+ auto with zarith.
+ intros Hz1; rewrite Zmod_def_small; auto with zarith.
+ match type of H5 with -?X + ?Y = ?Z =>
+ assert (V: Y = Z + X);
+ try (rewrite <- H5; ring)
+ end.
+ split.
+ unfold zn2z_to_Z; rewrite <- Hw1.
+ unfold ww_to_Z, zn2z_to_Z in H1; rewrite H1.
+ rewrite <- Hw0.
+ match goal with |- (?X ^2 + ?Y) * wwB + (?Z * wB + ?T) = ?U =>
+ apply trans_equal with ((X * wB) ^ 2 + (Y * wB + Z) * wB + T)
+ end.
+ repeat rewrite Zsquare_mult.
+ rewrite wwB_wBwB; ring.
+ rewrite H3.
+ rewrite V.
+ rewrite Hz1.
+ unfold ww_to_Z; simpl zn2z_to_Z.
+ repeat rewrite Zsquare_mult; ring.
+ rewrite Hz1.
+ destruct (spec_ww_to_Z w_digits w_to_Z spec_to_Z z);auto with zarith.
+ assert (V1 := spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW w4 w5)).
+ assert (0 < [[WW w4 w5]]); auto with zarith.
+ apply Zlt_le_trans with (wB/ 2 * wB + 0); auto with zarith.
+ autorewrite with rm10; apply Zmult_lt_0_compat; auto with zarith.
+ apply Zmult_lt_reg_r with 2; auto with zarith.
+ autorewrite with rm10.
+ rewrite Zmult_comm; rewrite wB_div_2; auto with zarith.
+ case (spec_to_Z w5);auto with zarith.
+ case (spec_to_Z w5);auto with zarith.
+ simpl.
+ assert (V2 := spec_to_Z w5);auto with zarith.
+ assert (V1 := spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW w4 w5)); auto with zarith.
+ split; auto with zarith.
+ assert (wwB <= 2 * [[WW w4 w5]]); auto with zarith.
+ apply Zle_trans with (2 * ([|w4|] * wB)).
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ rewrite Zmult_assoc; apply Zmult_le_compat_r; auto with zarith.
+ rewrite <- wB_div_2; auto with zarith.
+ assert (V2 := spec_to_Z w5);auto with zarith.
+ simpl ww_to_Z; assert (V2 := spec_to_Z w5);auto with zarith.
+ assert (V1 := spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW w4 w5)); auto with zarith.
+ intros z1; change [-[C1 z1]] with (-wwB + [[z1]]).
+ match goal with |- context[([+[C0 ?z]])] =>
+ change [+[C0 z]] with ([[z]])
+ end.
+ rewrite spec_ww_add; auto with zarith.
+ rewrite spec_ww_pred; auto with zarith.
+ rewrite ww_add_mult_mult_2.
+ assert (VV1 := spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW w4 w5)).
+ assert (VV2: 0 < [[WW w4 w5]]); auto with zarith.
+ apply Zlt_le_trans with (wB/ 2 * wB + 0); auto with zarith.
+ autorewrite with rm10; apply Zmult_lt_0_compat; auto with zarith.
+ apply Zmult_lt_reg_r with 2; auto with zarith.
+ autorewrite with rm10.
+ rewrite Zmult_comm; rewrite wB_div_2; auto with zarith.
+ assert (VV3 := spec_to_Z w5);auto with zarith.
+ assert (VV3 := spec_to_Z w5);auto with zarith.
+ simpl.
+ assert (VV3 := spec_to_Z w5);auto with zarith.
+ assert (VV3: wwB <= 2 * [[WW w4 w5]]); auto with zarith.
+ apply Zle_trans with (2 * ([|w4|] * wB)).
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ rewrite Zmult_assoc; apply Zmult_le_compat_r; auto with zarith.
+ rewrite <- wB_div_2; auto with zarith.
+ case (spec_to_Z w5);auto with zarith.
+ simpl ww_to_Z; assert (V4 := spec_to_Z w5);auto with zarith.
+ rewrite <- Zmod_unique with (q := 1) (r := -wwB + 2 * [[WW w4 w5]]);
+ auto with zarith.
+ intros Hz1; rewrite Zmod_def_small; auto with zarith.
+ match type of H5 with -?X + ?Y = ?Z =>
+ assert (V: Y = Z + X);
+ try (rewrite <- H5; ring)
+ end.
+ match type of Hz1 with -?X + ?Y = -?X + ?Z - 1 =>
+ assert (V1: Y = Z - 1);
+ [replace (Z - 1) with (X + (-X + Z -1));
+ [rewrite <- Hz1 | idtac]; ring
+ | idtac]
+ end.
+ rewrite <- Zmod_unique with (q := 1) (r := -wwB + [[z1]] + [[z]]);
+ auto with zarith.
+ unfold zn2z_to_Z; rewrite <- Hw1.
+ unfold ww_to_Z, zn2z_to_Z in H1; rewrite H1.
+ rewrite <- Hw0.
+ split.
+ match goal with |- (?X ^2 + ?Y) * wwB + (?Z * wB + ?T) = ?U =>
+ apply trans_equal with ((X * wB) ^ 2 + (Y * wB + Z) * wB + T)
+ end.
+ repeat rewrite Zsquare_mult.
+ rewrite wwB_wBwB; ring.
+ rewrite H3.
+ rewrite V.
+ rewrite Hz1.
+ unfold ww_to_Z; simpl zn2z_to_Z.
+ repeat rewrite Zsquare_mult; ring.
+ assert (V2 := spec_ww_to_Z w_digits w_to_Z spec_to_Z z);auto with zarith.
+ assert (V2 := spec_ww_to_Z w_digits w_to_Z spec_to_Z z);auto with zarith.
+ assert (V3 := spec_ww_to_Z w_digits w_to_Z spec_to_Z z1);auto with zarith.
+ split; auto with zarith.
+ rewrite (Zplus_comm (-wwB)); rewrite <- Zplus_assoc.
+ rewrite H5.
+ match goal with |- 0 <= ?X + (?Y - ?Z) =>
+ apply Zle_trans with (X - Z); auto with zarith
+ end.
+ 2: generalize (spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW w6 w1)); unfold ww_to_Z; auto with zarith.
+ rewrite V1.
+ match goal with |- 0 <= ?X - 1 - ?Y =>
+ assert (Y < X); auto with zarith
+ end.
+ apply Zlt_le_trans with wwB; auto with zarith.
+ intros (H3, H4).
+ match goal with |- context [ww_sub_c ?y ?z] =>
+ generalize (spec_ww_sub_c y z); case (ww_sub_c y z)
+ end.
+ intros z; change [-[C0 z]] with ([[z]]).
+ match goal with |- context[([+[C1 ?z]])] =>
+ replace [+[C1 z]] with (wwB + [[z]])
+ end.
+ 2: simpl; case wwB; auto.
+ intros H5; rewrite spec_w_square_c in H5;
+ auto.
+ split.
+ change ([||WW x y||]) with ([[x]] * wwB + [[y]]).
+ rewrite <- Hw1.
+ unfold ww_to_Z, zn2z_to_Z in H1; rewrite H1.
+ rewrite <- Hw0.
+ match goal with |- (?X ^2 + ?Y) * wwB + (?Z * wB + ?T) = ?U =>
+ apply trans_equal with ((X * wB) ^ 2 + (Y * wB + Z) * wB + T)
+ end.
+ repeat rewrite Zsquare_mult.
+ rewrite wwB_wBwB; ring.
+ rewrite H3.
+ rewrite H5.
+ unfold ww_to_Z; simpl zn2z_to_Z.
+ rewrite wwB_wBwB.
+ repeat rewrite Zsquare_mult; ring.
+ simpl ww_to_Z.
+ rewrite H5.
+ simpl ww_to_Z.
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ match goal with |- ?X * ?Y + (?Z * ?Y + ?T - ?U) <= _ =>
+ apply Zle_trans with (X * Y + (Z * Y + T - 0));
+ auto with zarith
+ end.
+ assert (V := Zsquare_pos [|w5|]);
+ rewrite Zsquare_mult in V; auto with zarith.
+ autorewrite with rm10.
+ match goal with |- _ <= 2 * (?U * ?V + ?W) =>
+ apply Zle_trans with (2 * U * V + 0);
+ auto with zarith
+ end.
+ match goal with |- ?X * ?Y + (?Z * ?Y + ?T) <= _ =>
+ replace (X * Y + (Z * Y + T)) with ((X + Z) * Y + T);
+ try ring
+ end.
+ apply Zlt_le_weak; apply beta_lex_inv; auto with zarith.
+ destruct (spec_to_Z w1);auto with zarith.
+ destruct (spec_to_Z w5);auto with zarith.
+ rewrite Zmult_plus_distr_r; auto with zarith.
+ rewrite Zmult_assoc; auto with zarith.
+ intros z; replace [-[C1 z]] with (- wwB + [[z]]).
+ 2: simpl; case wwB; auto with zarith.
+ intros H5; rewrite spec_w_square_c in H5;
+ auto.
+ match goal with |- context[([+[C0 ?z]])] =>
+ change [+[C0 z]] with ([[z]])
+ end.
+ match type of H5 with -?X + ?Y = ?Z =>
+ assert (V: Y = Z + X);
+ try (rewrite <- H5; ring)
+ end.
+ change ([||WW x y||]) with ([[x]] * wwB + [[y]]).
+ simpl ww_to_Z.
+ rewrite <- Hw1.
+ simpl ww_to_Z in H1; rewrite H1.
+ rewrite <- Hw0.
+ split.
+ match goal with |- (?X ^2 + ?Y) * wwB + (?Z * wB + ?T) = ?U =>
+ apply trans_equal with ((X * wB) ^ 2 + (Y * wB + Z) * wB + T)
+ end.
+ repeat rewrite Zsquare_mult.
+ rewrite wwB_wBwB; ring.
+ rewrite H3.
+ rewrite V.
+ simpl ww_to_Z.
+ rewrite wwB_wBwB.
+ repeat rewrite Zsquare_mult; ring.
+ rewrite V.
+ simpl ww_to_Z.
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ match goal with |- (?Z * ?Y + ?T - ?U) + ?X * ?Y <= _ =>
+ apply Zle_trans with ((Z * Y + T - 0) + X * Y);
+ auto with zarith
+ end.
+ assert (V1 := Zsquare_pos [|w5|]);
+ rewrite Zsquare_mult in V1; auto with zarith.
+ autorewrite with rm10.
+ match goal with |- _ <= 2 * (?U * ?V + ?W) =>
+ apply Zle_trans with (2 * U * V + 0);
+ auto with zarith
+ end.
+ match goal with |- (?Z * ?Y + ?T) + ?X * ?Y <= _ =>
+ replace ((Z * Y + T) + X * Y) with ((X + Z) * Y + T);
+ try ring
+ end.
+ apply Zlt_le_weak; apply beta_lex_inv; auto with zarith.
+ destruct (spec_to_Z w1);auto with zarith.
+ destruct (spec_to_Z w5);auto with zarith.
+ rewrite Zmult_plus_distr_r; auto with zarith.
+ rewrite Zmult_assoc; auto with zarith.
+ case Zle_lt_or_eq with (1 := H2); clear H2; intros H2.
+ intros c1 (H3, H4).
+ match type of H3 with ?X = ?Y =>
+ absurd (X < Y)
+ end.
+ apply Zle_not_lt; rewrite <- H3; auto with zarith.
+ rewrite Zmult_plus_distr_l.
+ apply Zlt_le_trans with ((2 * [|w4|]) * wB + 0);
+ auto with zarith.
+ apply beta_lex_inv; auto with zarith.
+ destruct (spec_to_Z w0);auto with zarith.
+ assert (V1 := spec_to_Z w5);auto with zarith.
+ rewrite (Zmult_comm wB); auto with zarith.
+ assert (0 <= [|w5|] * (2 * [|w4|])); auto with zarith.
+ intros c1 (H3, H4); rewrite H2 in H3.
+ match type of H3 with ?X + ?Y = (?Z + ?T) * ?U + ?V =>
+ assert (VV: (Y = (T * U) + V));
+ [replace Y with ((X + Y) - X);
+ [rewrite H3; ring | ring] | idtac]
+ end.
+ assert (V1 := spec_to_Z w0);auto with zarith.
+ assert (V2 := spec_to_Z w5);auto with zarith.
+ case (Zle_lt_or_eq 0 [|w5|]); auto with zarith; intros V3.
+ match type of VV with ?X = ?Y =>
+ absurd (X < Y)
+ end.
+ apply Zle_not_lt; rewrite <- VV; auto with zarith.
+ apply Zlt_le_trans with wB; auto with zarith.
+ match goal with |- _ <= ?X + _ =>
+ apply Zle_trans with X; auto with zarith
+ end.
+ match goal with |- _ <= _ * ?X =>
+ apply Zle_trans with (1 * X); auto with zarith
+ end.
+ autorewrite with rm10.
+ rewrite <- wB_div_2; apply Zmult_le_compat_l; auto with zarith.
+ rewrite <- V3 in VV; generalize VV; autorewrite with rm10;
+ clear VV; intros VV.
+ rewrite spec_ww_add_c; auto with zarith.
+ rewrite ww_add_mult_mult_2_plus_1.
+ match goal with |- context[?X mod wwB] =>
+ rewrite <- Zmod_unique with (q := 1) (r := -wwB + X)
+ end; auto with zarith.
+ simpl ww_to_Z.
+ rewrite spec_w_Bm1; auto with zarith.
+ split.
+ change ([||WW x y||]) with ([[x]] * wwB + [[y]]).
+ rewrite <- Hw1.
+ simpl ww_to_Z in H1; rewrite H1.
+ rewrite <- Hw0.
+ match goal with |- (?X ^2 + ?Y) * wwB + (?Z * wB + ?T) = ?U =>
+ apply trans_equal with ((X * wB) ^ 2 + (Y * wB + Z) * wB + T)
+ end.
+ repeat rewrite Zsquare_mult.
+ rewrite wwB_wBwB; ring.
+ rewrite H2.
+ rewrite wwB_wBwB.
+ repeat rewrite Zsquare_mult; ring.
+ assert (V4 := spec_ww_to_Z w_digits w_to_Z spec_to_Z y);auto with zarith.
+ assert (V4 := spec_ww_to_Z w_digits w_to_Z spec_to_Z y);auto with zarith.
+ simpl ww_to_Z; unfold ww_to_Z.
+ rewrite spec_w_Bm1; auto with zarith.
+ split.
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ match goal with |- _ <= -?X + (2 * (?Z * ?T + ?U) + ?V) =>
+ assert (X <= 2 * Z * T); auto with zarith
+ end.
+ apply Zmult_le_compat_r; auto with zarith.
+ rewrite <- wB_div_2; apply Zmult_le_compat_l; auto with zarith.
+ rewrite Zmult_plus_distr_r; auto with zarith.
+ rewrite Zmult_assoc; auto with zarith.
+ match goal with |- _ + ?X < _ =>
+ replace X with ((2 * (([|w4|]) + 1) * wB) - 1); try ring
+ end.
+ assert (2 * ([|w4|] + 1) * wB <= 2 * wwB); auto with zarith.
+ rewrite <- Zmult_assoc; apply Zmult_le_compat_l; auto with zarith.
+ rewrite wwB_wBwB; rewrite Zpower_2.
+ apply Zmult_le_compat_r; auto with zarith.
+ case (spec_to_Z w4);auto with zarith.
+ Qed.
+
+ Lemma spec_ww_is_zero: forall x,
+ if ww_is_zero x then [[x]] = 0 else 0 < [[x]].
+ intro x; unfold ww_is_zero.
+ generalize (spec_ww_compare W0 x); case (ww_compare W0 x);
+ auto with zarith.
+ simpl ww_to_Z.
+ assert (V4 := spec_ww_to_Z w_digits w_to_Z spec_to_Z x);auto with zarith.
+ Qed.
+
+ Lemma Zdiv_le_monotone: forall p q r, 0 <= p -> 0 < q < r ->
+ p / r <= p / q.
+ intros p q r H H1.
+ apply Zdiv_le_lower_bound; auto with zarith.
+ rewrite Zmult_comm.
+ pattern p at 2; rewrite (Z_div_mod_eq p r); auto with zarith.
+ apply Zle_trans with (r * (p / r)); auto with zarith.
+ case (Z_mod_lt p r); auto with zarith.
+ Qed.
+
+ Lemma wwB_4_2: 2 * (wwB / 4) = wwB/ 2.
+ pattern wwB at 1; rewrite wwB_wBwB; rewrite Zpower_2.
+ rewrite <- wB_div_2.
+ match goal with |- context[(2 * ?X) * (2 * ?Z)] =>
+ replace ((2 * X) * (2 * Z)) with ((X * Z) * 4); try ring
+ end.
+ rewrite Z_div_mult; auto with zarith.
+ rewrite Zmult_assoc; rewrite wB_div_2.
+ rewrite wwB_div_2; ring.
+ Qed.
+
+
+ Lemma spec_ww_head1
+ : forall x : zn2z w,
+ (forall p, ww_head1 x = Npos p -> (2 * Zpos (Pdiv2 p) = Zpos p)) /\
+ (0 < [[x]] -> wwB / 4 <= 2 ^ Z_of_N (ww_head1 x) * [[x]] < wwB).
+ assert (U := wB_pos w_digits).
+ intros x; unfold ww_head1.
+ generalize (spec_ww_head0 x); case (ww_head0 x); simpl Z_of_N;
+ autorewrite with rm10.
+ intros H1; split.
+ intros; discriminate.
+ intros H2; assert (H3:= H1 H2).
+ split; auto with zarith.
+ apply Zle_trans with (wwB/2); auto with zarith.
+ apply Zdiv_le_monotone; auto with zarith.
+ intros p; case p; clear p; simpl Z_of_N.
+ intros p H1; split.
+ intros p1 H2; injection H2; intros; subst; clear H2; auto.
+ intros H2; assert (H3:= H1 H2).
+ split; auto with zarith.
+ apply Zmult_le_reg_r with 2; auto with zarith.
+ repeat rewrite (fun x => Zmult_comm x 2).
+ rewrite wwB_4_2.
+ pattern 2 at 2; rewrite <- Zpower_exp_1; rewrite Zmult_assoc;
+ rewrite <- Zpower_exp; auto with zarith.
+ replace (1 + Zpos (xO p)) with (Zpos (xI p)); auto with zarith.
+ case H3; intros _ tmp; apply Zlt_trans with (2 := tmp).
+ apply Zmult_lt_compat_r; auto with zarith.
+ apply Zpower_lt_monotone; auto with zarith.
+ split; try (red; intros; discriminate).
+ replace (Zpos (xI p)) with (1 + Zpos (xO p)); auto with zarith.
+ intros p H1; split.
+ intros p1 H2; injection H2; intros; subst; clear H2; auto.
+ intros H2; assert (H3:= H1 H2).
+ split; auto with zarith.
+ apply Zle_trans with (wwB/2); auto with zarith.
+ apply Zdiv_le_monotone; auto with zarith.
+ generalize (wwB_pos w_digits); auto with zarith.
+ rewrite Zpower_exp_1; try rewrite Zpower_exp_0.
+ intros H1; split.
+ intros; discriminate.
+ intros H2; assert (H3 := H1 H2).
+ autorewrite with rm10.
+ split; auto with zarith.
+ apply Zmult_le_reg_r with 2; auto with zarith.
+ repeat rewrite (fun x => Zmult_comm x 2).
+ rewrite wwB_4_2; auto with zarith.
+ Qed.
+
+ Theorem wwB_4_wB_4: wwB / 4 = wB / 4 * wB.
+ apply sym_equal; apply Zdiv_unique with 0;
+ auto with zarith.
+ rewrite Zmult_assoc; rewrite wB_div_4; auto with zarith.
+ rewrite wwB_wBwB; ring.
+ Qed.
+
+ Lemma spec_ww_sqrt : forall x,
+ [[ww_sqrt x]] ^ 2 <= [[x]] < ([[ww_sqrt x]] + 1) ^ 2.
+ assert (U := wB_pos w_digits).
+ intro x; unfold ww_sqrt.
+ generalize (spec_ww_is_zero x); case (ww_is_zero x).
+ simpl ww_to_Z; simpl Zpower; unfold Zpower_pos; simpl;
+ auto with zarith.
+ intros H1; generalize (spec_ww_head1 x); case (ww_head1 x); simpl Z_of_N;
+ autorewrite with rm10.
+ generalize H1; case x.
+ intros HH; contradict HH; simpl ww_to_Z; auto with zarith.
+ intros w0 w1; simpl ww_to_Z; autorewrite with w_rewrite rm10.
+ intros H2 (H3, H4).
+ generalize (H4 H2); clear H4; intros (H4, H5).
+ assert (V: wB/4 <= [|w0|]).
+ apply beta_lex with 0 [|w1|] wB; auto with zarith; autorewrite with rm10.
+ rewrite <- wwB_4_wB_4; auto.
+ generalize (@spec_w_sqrt2 w0 w1 V);auto with zarith.
+ case (w_sqrt2 w0 w1); intros w2 c.
+ simpl ww_to_Z; simpl fst.
+ case c; unfold interp_carry; autorewrite with rm10.
+ intros w3 (H6, H7); rewrite H6.
+ assert (V1 := spec_to_Z w3);auto with zarith.
+ split; auto with zarith.
+ apply Zle_lt_trans with ([|w2|] ^2 + 2 * [|w2|]); auto with zarith.
+ match goal with |- ?X < ?Z =>
+ replace Z with (X + 1); auto with zarith
+ end.
+ repeat rewrite Zsquare_mult; ring.
+ intros w3 (H6, H7); rewrite H6.
+ assert (V1 := spec_to_Z w3);auto with zarith.
+ split; auto with zarith.
+ apply Zle_lt_trans with ([|w2|] ^2 + 2 * [|w2|]); auto with zarith.
+ match goal with |- ?X < ?Z =>
+ replace Z with (X + 1); auto with zarith
+ end.
+ repeat rewrite Zsquare_mult; ring.
+ intros p (Hp1, Hp2).
+ assert (F0: 0 < Zpos (Pdiv2 p)); try (red; reflexivity).
+ assert (Hp3 := Hp1 p (refl_equal _)).
+ assert (U0: Zpos p < Zpos (ww_digits w_digits)).
+ case (Zle_or_lt (Zpos (ww_digits w_digits)) (Zpos p)); auto; intros H2;
+ case (Hp2 H1); intros _ tmp; contradict tmp; apply Zle_not_lt;
+ unfold base.
+ apply Zle_trans with (2 ^ Zpos p * 1); auto with zarith.
+ autorewrite with rm10; apply Zpower_le_monotone; auto with zarith.
+ assert (U1: Zpos (Pdiv2 p) < Zpos (ww_digits w_digits)); auto with zarith.
+ match goal with |- context[ww_add_mul_div ?y ?z ?t] =>
+ assert (UU:= spec_ww_add_mul_div z t );
+ generalize (UU p U0);
+ case (ww_add_mul_div y z t)
+ end.
+ simpl ww_to_Z; autorewrite with w_rewrite rm10.
+ rewrite Zmod_def_small; auto with zarith.
+ intros H2; case (Zmult_integral _ _ (sym_equal H2)); clear H2; intros H2.
+ rewrite H2; unfold Zpower, Zpower_pos; simpl; auto with zarith.
+ match type of H2 with ?X = ?Y =>
+ absurd (Y < X); try (rewrite H2; auto with zarith; fail)
+ end.
+ apply Zpower_lt_0; auto with zarith.
+ split; auto with zarith.
+ case (Hp2 H1); intros _ tmp; apply Zle_lt_trans with (2 := tmp);
+ clear tmp.
+ rewrite Zmult_comm; apply Zmult_le_compat_r; auto with zarith.
+ intros w0 w1; autorewrite with w_rewrite rm10.
+ rewrite Zmod_def_small; auto with zarith.
+ 2: rewrite Zmult_comm; auto with zarith.
+ intros H2.
+ assert (V: wB/4 <= [|w0|]).
+ apply beta_lex with 0 [|w1|] wB; auto with zarith; autorewrite with rm10.
+ simpl ww_to_Z in H2; rewrite H2.
+ rewrite <- wwB_4_wB_4; auto with zarith.
+ rewrite Zmult_comm; auto with zarith.
+ assert (V1 := spec_to_Z w1);auto with zarith.
+ generalize (@spec_w_sqrt2 w0 w1 V);auto with zarith.
+ case (w_sqrt2 w0 w1); intros w2 c.
+ simpl ww_to_Z; simpl fst.
+ assert (U2: Zpos (Pdiv2 p) < Zpos w_digits).
+ apply Zmult_lt_reg_r with 2; auto with zarith.
+ repeat rewrite (fun x => Zmult_comm x 2).
+ rewrite Hp3.
+ rewrite <- Zpos_xO; auto.
+ autorewrite with w_rewrite rm10.
+ 2: rewrite Zpos_minus; auto with zarith; auto.
+ rewrite Zpos_minus; auto with zarith.
+ match goal with |- context[?X - (?X -?Y)] =>
+ replace (X - (X - Y)) with Y; try ring
+ end.
+ assert (V2 := spec_to_Z w2);auto with zarith.
+ rewrite Zmod_def_small; auto with zarith.
+ simpl ww_to_Z in H2; rewrite H2; auto with zarith.
+ intros (H4, H5); split.
+ apply Zmult_le_reg_r with (2 ^ Zpos p); auto with zarith.
+ rewrite H4.
+ apply Zle_trans with ([|w2|] ^ 2); auto with zarith.
+ repeat rewrite (fun x => Zmult_comm x (2 ^ Zpos p)).
+ rewrite <- Hp3; rewrite (Zmult_comm 2); rewrite Zpower_mult;
+ auto with zarith.
+ assert (tmp: forall p q, p ^ 2 * q ^ 2 = (p * q) ^2);
+ try (intros; repeat rewrite Zsquare_mult; ring);
+ rewrite tmp; clear tmp.
+ apply ZPowerAux.Zpower_le_monotone_exp; auto with zarith.
+ split; auto with zarith.
+ pattern [|w2|] at 2; rewrite (Z_div_mod_eq [|w2|] (2 ^ Zpos (Pdiv2 p)));
+ auto with zarith.
+ match goal with |- ?X <= ?X + ?Y =>
+ assert (0 <= Y); auto with zarith
+ end.
+ case (Z_mod_lt [|w2|] (2 ^ Zpos (Pdiv2 p))); auto with zarith.
+ case c; unfold interp_carry; autorewrite with rm10;
+ intros w3; assert (V3 := spec_to_Z w3);auto with zarith.
+ apply Zmult_lt_reg_r with (2 ^ Zpos p); auto with zarith.
+ rewrite H4.
+ apply Zle_lt_trans with ([|w2|] ^ 2 + 2 * [|w2|]); auto with zarith.
+ apply Zlt_le_trans with (([|w2|] + 1) ^ 2); auto with zarith.
+ match goal with |- ?X < ?Y =>
+ replace Y with (X + 1); auto with zarith
+ end.
+ repeat rewrite (Zsquare_mult); ring.
+ repeat rewrite (fun x => Zmult_comm x (2 ^ Zpos p)).
+ rewrite <- Hp3; rewrite (Zmult_comm 2); rewrite Zpower_mult;
+ auto with zarith.
+ assert (tmp: forall p q, p ^ 2 * q ^ 2 = (p * q) ^2);
+ try (intros; repeat rewrite Zsquare_mult; ring);
+ rewrite tmp; clear tmp.
+ apply ZPowerAux.Zpower_le_monotone_exp; auto with zarith.
+ split; auto with zarith.
+ pattern [|w2|] at 1; rewrite (Z_div_mod_eq [|w2|] (2 ^ Zpos (Pdiv2 p)));
+ auto with zarith.
+ rewrite <- Zplus_assoc; rewrite Zmult_plus_distr_r.
+ autorewrite with rm10; apply Zplus_le_compat_l; auto with zarith.
+ case (Z_mod_lt [|w2|] (2 ^ Zpos (Pdiv2 p))); auto with zarith.
+ split; auto with zarith.
+ apply Zle_lt_trans with ([|w2|]); auto with zarith.
+ apply Zdiv_le_upper_bound; auto with zarith.
+ pattern [|w2|] at 1; replace [|w2|] with ([|w2|] * 2 ^0);
+ auto with zarith.
+ apply Zmult_le_compat_l; auto with zarith.
+ apply Zpower_le_monotone; auto with zarith.
+ rewrite Zpower_exp_0; autorewrite with rm10; auto.
+ Qed.
+
+End GenSqrt.
diff --git a/theories/Ints/num/GenSub.v b/theories/Ints/num/GenSub.v
new file mode 100644
index 0000000000..43661edd5b
--- /dev/null
+++ b/theories/Ints/num/GenSub.v
@@ -0,0 +1,354 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section GenSub.
+ Variable w : Set.
+ Variable w_0 : w.
+ Variable w_Bm1 : w.
+ Variable w_WW : w -> w -> zn2z w.
+ Variable ww_Bm1 : zn2z w.
+ Variable w_opp_c : w -> carry w.
+ Variable w_opp_carry : w -> w.
+ Variable w_pred_c : w -> carry w.
+ Variable w_sub_c : w -> w -> carry w.
+ Variable w_sub_carry_c : w -> w -> carry w.
+ Variable w_opp : w -> w.
+ Variable w_pred : w -> w.
+ Variable w_sub : w -> w -> w.
+ Variable w_sub_carry : w -> w -> w.
+
+ (* ** Opposites ** *)
+ Definition ww_opp_c x :=
+ match x with
+ | W0 => C0 W0
+ | WW xh xl =>
+ match w_opp_c xl with
+ | C0 _ =>
+ match w_opp_c xh with
+ | C0 h => C0 W0
+ | C1 h => C1 (WW h w_0)
+ end
+ | C1 l => C1 (WW (w_opp_carry xh) l)
+ end
+ end.
+
+ Definition ww_opp x :=
+ match x with
+ | W0 => W0
+ | WW xh xl =>
+ match w_opp_c xl with
+ | C0 _ => WW (w_opp xh) w_0
+ | C1 l => WW (w_opp_carry xh) l
+ end
+ end.
+
+ Definition ww_opp_carry x :=
+ match x with
+ | W0 => ww_Bm1
+ | WW xh xl => w_WW (w_opp_carry xh) (w_opp_carry xl)
+ end.
+
+ Definition ww_pred_c x :=
+ match x with
+ | W0 => C1 ww_Bm1
+ | WW xh xl =>
+ match w_pred_c xl with
+ | C0 l => C0 (w_WW xh l)
+ | C1 _ =>
+ match w_pred_c xh with
+ | C0 h => C0 (WW h w_Bm1)
+ | C1 _ => C1 ww_Bm1
+ end
+ end
+ end.
+
+ Definition ww_pred x :=
+ match x with
+ | W0 => ww_Bm1
+ | WW xh xl =>
+ match w_pred_c xl with
+ | C0 l => w_WW xh l
+ | C1 l => WW (w_pred xh) w_Bm1
+ end
+ end.
+
+ Definition ww_sub_c x y :=
+ match y, x with
+ | W0, _ => C0 x
+ | WW yh yl, W0 => ww_opp_c (WW yh yl)
+ | WW yh yl, WW xh xl =>
+ match w_sub_c xl yl with
+ | C0 l =>
+ match w_sub_c xh yh with
+ | C0 h => C0 (w_WW h l)
+ | C1 h => C1 (WW h l)
+ end
+ | C1 l =>
+ match w_sub_carry_c xh yh with
+ | C0 h => C0 (WW h l)
+ | C1 h => C1 (WW h l)
+ end
+ end
+ end.
+
+ Definition ww_sub x y :=
+ match y, x with
+ | W0, _ => x
+ | WW yh yl, W0 => ww_opp (WW yh yl)
+ | WW yh yl, WW xh xl =>
+ match w_sub_c xl yl with
+ | C0 l => w_WW (w_sub xh yh) l
+ | C1 l => WW (w_sub_carry xh yh) l
+ end
+ end.
+
+ Definition ww_sub_carry_c x y :=
+ match y, x with
+ | W0, W0 => C1 ww_Bm1
+ | W0, WW xh xl => ww_pred_c (WW xh xl)
+ | WW yh yl, W0 => C1 (ww_opp_carry (WW yh yl))
+ | WW yh yl, WW xh xl =>
+ match w_sub_carry_c xl yl with
+ | C0 l =>
+ match w_sub_c xh yh with
+ | C0 h => C0 (w_WW h l)
+ | C1 h => C1 (WW h l)
+ end
+ | C1 l =>
+ match w_sub_carry_c xh yh with
+ | C0 h => C0 (w_WW h l)
+ | C1 h => C1 (w_WW h l)
+ end
+ end
+ end.
+
+ Definition ww_sub_carry x y :=
+ match y, x with
+ | W0, W0 => ww_Bm1
+ | W0, WW xh xl => ww_pred (WW xh xl)
+ | WW yh yl, W0 => ww_opp_carry (WW yh yl)
+ | WW yh yl, WW xh xl =>
+ match w_sub_carry_c xl yl with
+ | C0 l => w_WW (w_sub xh yh) l
+ | C1 l => w_WW (w_sub_carry xh yh) l
+ end
+ end.
+
+ (*Section GenProof.*)
+ Variable w_digits : positive.
+ Variable w_to_Z : w -> Z.
+
+
+ Notation wB := (base w_digits).
+ Notation wwB := (base (ww_digits w_digits)).
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+ Notation "[+| c |]" :=
+ (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (ww_to_Z w_digits w_to_Z x)(at level 0, x at level 99).
+ Notation "[+[ c ]]" :=
+ (interp_carry 1 wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+ Notation "[-[ c ]]" :=
+ (interp_carry (-1) wwB (ww_to_Z w_digits w_to_Z) c)
+ (at level 0, x at level 99).
+
+ Variable spec_w_0 : [|w_0|] = 0.
+ Variable spec_w_Bm1 : [|w_Bm1|] = wB - 1.
+ Variable spec_ww_Bm1 : [[ww_Bm1]] = wwB - 1.
+ Variable spec_to_Z : forall x, 0 <= [|x|] < wB.
+ Variable spec_w_WW : forall h l, [[w_WW h l]] = [|h|] * wB + [|l|].
+
+ Variable spec_opp_c : forall x, [-|w_opp_c x|] = -[|x|].
+ Variable spec_opp : forall x, [|w_opp x|] = (-[|x|]) mod wB.
+ Variable spec_opp_carry : forall x, [|w_opp_carry x|] = wB - [|x|] - 1.
+
+ Variable spec_pred_c : forall x, [-|w_pred_c x|] = [|x|] - 1.
+ Variable spec_sub_c : forall x y, [-|w_sub_c x y|] = [|x|] - [|y|].
+ Variable spec_sub_carry_c :
+ forall x y, [-|w_sub_carry_c x y|] = [|x|] - [|y|] - 1.
+
+ Variable spec_pred : forall x, [|w_pred x|] = ([|x|] - 1) mod wB.
+ Variable spec_sub : forall x y, [|w_sub x y|] = ([|x|] - [|y|]) mod wB.
+ Variable spec_sub_carry :
+ forall x y, [|w_sub_carry x y|] = ([|x|] - [|y|] - 1) mod wB.
+
+
+ Lemma spec_ww_opp_c : forall x, [-[ww_opp_c x]] = -[[x]].
+ Proof.
+ destruct x as [ |xh xl];simpl. reflexivity.
+ rewrite Zopp_plus_distr;generalize (spec_opp_c xl);destruct (w_opp_c xl)
+ as [l|l];intros H;unfold interp_carry in H;rewrite <- H;
+ rewrite Zopp_mult_distr_l.
+ assert ([|l|] = 0).
+ assert (H1:= spec_to_Z l);assert (H2 := spec_to_Z xl);omega.
+ rewrite H0;generalize (spec_opp_c xh);destruct (w_opp_c xh)
+ as [h|h];intros H1;unfold interp_carry in *;rewrite <- H1.
+ assert ([|h|] = 0).
+ assert (H3:= spec_to_Z h);assert (H2 := spec_to_Z xh);omega.
+ rewrite H2;reflexivity.
+ simpl ww_to_Z;rewrite wwB_wBwB;rewrite spec_w_0;ring.
+ unfold interp_carry;simpl ww_to_Z;rewrite wwB_wBwB;rewrite spec_opp_carry;
+ ring.
+ Qed.
+
+ Lemma spec_ww_opp : forall x, [[ww_opp x]] = (-[[x]]) mod wwB.
+ Proof.
+ destruct x as [ |xh xl];simpl. reflexivity.
+ rewrite Zopp_plus_distr;rewrite Zopp_mult_distr_l.
+ generalize (spec_opp_c xl);destruct (w_opp_c xl)
+ as [l|l];intros H;unfold interp_carry in H;rewrite <- H;simpl ww_to_Z.
+ rewrite spec_w_0;rewrite Zplus_0_r;rewrite wwB_wBwB.
+ assert ([|l|] = 0).
+ assert (H1:= spec_to_Z l);assert (H2 := spec_to_Z xl);omega.
+ rewrite H0;rewrite Zplus_0_r; rewrite Zpower_2;
+ rewrite Zmult_mod_distr_r;try apply lt_0_wB.
+ rewrite spec_opp;trivial.
+ apply Zmod_unique with (q:= -1). apply lt_0_wwB.
+ exact (spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW (w_opp_carry xh) l)).
+ rewrite spec_opp_carry;rewrite wwB_wBwB;ring.
+ Qed.
+
+ Lemma spec_ww_opp_carry : forall x, [[ww_opp_carry x]] = wwB - [[x]] - 1.
+ Proof.
+ destruct x as [ |xh xl];simpl. rewrite spec_ww_Bm1;ring.
+ rewrite spec_w_WW;simpl;repeat rewrite spec_opp_carry;rewrite wwB_wBwB;ring.
+ Qed.
+
+ Lemma spec_ww_pred_c : forall x, [-[ww_pred_c x]] = [[x]] - 1.
+ Proof.
+ destruct x as [ |xh xl];unfold ww_pred_c.
+ unfold interp_carry;rewrite spec_ww_Bm1;simpl ww_to_Z;ring.
+ simpl ww_to_Z;replace (([|xh|]*wB+[|xl|])-1) with ([|xh|]*wB+([|xl|]-1)).
+ 2:ring. generalize (spec_pred_c xl);destruct (w_pred_c xl) as [l|l];
+ intros H;unfold interp_carry in H;rewrite <- H. simpl;apply spec_w_WW.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ assert ([|l|] = wB - 1).
+ assert (H1:= spec_to_Z l);assert (H2 := spec_to_Z xl);omega.
+ rewrite H0;change ([|xh|] + -1) with ([|xh|] - 1).
+ generalize (spec_pred_c xh);destruct (w_pred_c xh) as [h|h];
+ intros H1;unfold interp_carry in H1;rewrite <- H1.
+ simpl;rewrite spec_w_Bm1;ring.
+ assert ([|h|] = wB - 1).
+ assert (H3:= spec_to_Z h);assert (H2 := spec_to_Z xh);omega.
+ rewrite H2;unfold interp_carry;rewrite spec_ww_Bm1;rewrite wwB_wBwB;ring.
+ Qed.
+
+ Lemma spec_ww_sub_c : forall x y, [-[ww_sub_c x y]] = [[x]] - [[y]].
+ Proof.
+ destruct y as [ |yh yl];simpl. ring.
+ destruct x as [ |xh xl];simpl. exact (spec_ww_opp_c (WW yh yl)).
+ replace ([|xh|] * wB + [|xl|] - ([|yh|] * wB + [|yl|]))
+ with (([|xh|]-[|yh|])*wB + ([|xl|]-[|yl|])). 2:ring.
+ generalize (spec_sub_c xl yl);destruct (w_sub_c xl yl) as [l|l];intros H;
+ unfold interp_carry in H;rewrite <- H.
+ generalize (spec_sub_c xh yh);destruct (w_sub_c xh yh) as [h|h];intros H1;
+ unfold interp_carry in H1;rewrite <- H1;unfold interp_carry;
+ try rewrite spec_w_WW;simpl ww_to_Z;try rewrite wwB_wBwB;ring.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ change ([|xh|] - [|yh|] + -1) with ([|xh|] - [|yh|] - 1).
+ generalize (spec_sub_carry_c xh yh);destruct (w_sub_carry_c xh yh) as [h|h];
+ intros H1;unfold interp_carry in *;rewrite <- H1;simpl ww_to_Z;
+ try rewrite wwB_wBwB;ring.
+ Qed.
+
+ Lemma spec_ww_sub_carry_c :
+ forall x y, [-[ww_sub_carry_c x y]] = [[x]] - [[y]] - 1.
+ Proof.
+ destruct y as [ |yh yl];simpl.
+ unfold Zminus;simpl;rewrite Zplus_0_r;exact (spec_ww_pred_c x).
+ destruct x as [ |xh xl].
+ unfold interp_carry;rewrite spec_w_WW;simpl ww_to_Z;rewrite wwB_wBwB;
+ repeat rewrite spec_opp_carry;ring.
+ simpl ww_to_Z.
+ replace ([|xh|] * wB + [|xl|] - ([|yh|] * wB + [|yl|]) - 1)
+ with (([|xh|]-[|yh|])*wB + ([|xl|]-[|yl|]-1)). 2:ring.
+ generalize (spec_sub_carry_c xl yl);destruct (w_sub_carry_c xl yl)
+ as [l|l];intros H;unfold interp_carry in H;rewrite <- H.
+ generalize (spec_sub_c xh yh);destruct (w_sub_c xh yh) as [h|h];intros H1;
+ unfold interp_carry in H1;rewrite <- H1;unfold interp_carry;
+ try rewrite spec_w_WW;simpl ww_to_Z;try rewrite wwB_wBwB;ring.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ change ([|xh|] - [|yh|] + -1) with ([|xh|] - [|yh|] - 1).
+ generalize (spec_sub_carry_c xh yh);destruct (w_sub_carry_c xh yh) as [h|h];
+ intros H1;unfold interp_carry in *;rewrite <- H1;try rewrite spec_w_WW;
+ simpl ww_to_Z; try rewrite wwB_wBwB;ring.
+ Qed.
+
+ Lemma spec_ww_pred : forall x, [[ww_pred x]] = ([[x]] - 1) mod wwB.
+ Proof.
+ destruct x as [ |xh xl];simpl.
+ apply Zmod_unique with (-1). apply lt_0_wwB. apply spec_ww_to_Z;trivial.
+ rewrite spec_ww_Bm1;ring.
+ replace ([|xh|]*wB + [|xl|] - 1) with ([|xh|]*wB + ([|xl|] - 1)). 2:ring.
+ generalize (spec_pred_c xl);destruct (w_pred_c xl) as [l|l];intro H;
+ unfold interp_carry in H;rewrite <- H;simpl ww_to_Z.
+ rewrite Zmod_def_small. apply spec_w_WW.
+ exact (spec_ww_to_Z w_digits w_to_Z spec_to_Z (WW xh l)).
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ change ([|xh|] + -1) with ([|xh|] - 1).
+ assert ([|l|] = wB - 1).
+ assert (H1:= spec_to_Z l);assert (H2:= spec_to_Z xl);omega.
+ rewrite (mod_wwB w_digits w_to_Z);trivial.
+ rewrite spec_pred;rewrite spec_w_Bm1;rewrite <- H0;trivial.
+ Qed.
+
+ Lemma spec_ww_sub : forall x y, [[ww_sub x y]] = ([[x]] - [[y]]) mod wwB.
+ Proof.
+ destruct y as [ |yh yl];simpl.
+ ring_simplify ([[x]] - 0);rewrite Zmod_def_small;trivial. apply spec_ww_to_Z;trivial.
+ destruct x as [ |xh xl];simpl. exact (spec_ww_opp (WW yh yl)).
+ replace ([|xh|] * wB + [|xl|] - ([|yh|] * wB + [|yl|]))
+ with (([|xh|] - [|yh|]) * wB + ([|xl|] - [|yl|])). 2:ring.
+ generalize (spec_sub_c xl yl);destruct (w_sub_c xl yl)as[l|l];intros H;
+ unfold interp_carry in H;rewrite <- H.
+ rewrite spec_w_WW;rewrite (mod_wwB w_digits w_to_Z spec_to_Z).
+ rewrite spec_sub;trivial.
+ simpl ww_to_Z;rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ rewrite (mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_sub_carry;trivial.
+ Qed.
+
+ Lemma spec_ww_sub_carry :
+ forall x y, [[ww_sub_carry x y]] = ([[x]] - [[y]] - 1) mod wwB.
+ Proof.
+ destruct y as [ |yh yl];simpl.
+ ring_simplify ([[x]] - 0);exact (spec_ww_pred x).
+ destruct x as [ |xh xl];simpl.
+ apply Zmod_unique with (-1). apply lt_0_wwB.
+ apply spec_ww_to_Z;trivial.
+ fold (ww_opp_carry (WW yh yl)).
+ rewrite (spec_ww_opp_carry (WW yh yl));simpl ww_to_Z;ring.
+ replace ([|xh|] * wB + [|xl|] - ([|yh|] * wB + [|yl|]) - 1)
+ with (([|xh|] - [|yh|]) * wB + ([|xl|] - [|yl|] - 1)). 2:ring.
+ generalize (spec_sub_carry_c xl yl);destruct (w_sub_carry_c xl yl)as[l|l];
+ intros H;unfold interp_carry in H;rewrite <- H;rewrite spec_w_WW.
+ rewrite (mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_sub;trivial.
+ rewrite Zplus_assoc;rewrite <- Zmult_plus_distr_l.
+ rewrite (mod_wwB w_digits w_to_Z spec_to_Z);rewrite spec_sub_carry;trivial.
+ Qed.
+
+(* End GenProof. *)
+
+End GenSub.
+
+
+
+
+
diff --git a/theories/Ints/num/NMake.v b/theories/Ints/num/NMake.v
new file mode 100644
index 0000000000..c7cd3360fc
--- /dev/null
+++ b/theories/Ints/num/NMake.v
@@ -0,0 +1,3473 @@
+Require Import ZArith.
+Require Import Basic_type.
+Require Import ZnZ.
+Require Import Zn2Z.
+Require Import Nbasic.
+Require Import GenMul.
+Require Import GenDivn1.
+
+
+
+Fixpoint plength (p: positive) : positive :=
+ match p with
+ xH => xH
+ | xO p1 => Psucc (plength p1)
+ | xI p1 => Psucc (plength p1)
+ end.
+
+Definition pheight p := plength (Ppred (plength (Ppred p))).
+
+Module Type W0Type.
+ Parameter w : Set.
+ Parameter w_op : znz_op w.
+ Parameter w_spec : znz_spec w_op.
+End W0Type.
+
+Module Make (W0:W0Type).
+ Import W0.
+
+ Definition w0 := W0.w.
+ Definition w1 := zn2z w0.
+ Definition w2 := zn2z w1.
+ Definition w3 := zn2z w2.
+ Definition w4 := zn2z w3.
+ Definition w5 := zn2z w4.
+ Definition w6 := zn2z w5.
+ Definition w7 := zn2z w6.
+ Definition w8 := zn2z w7.
+ Definition w9 := zn2z w8.
+ Definition w10 := zn2z w9.
+ Definition w11 := zn2z w10.
+ Definition w12 := zn2z w11.
+
+ Definition w0_op := W0.w_op.
+ Definition w1_op := mk_zn2z_op w0_op.
+ Definition w2_op := mk_zn2z_op w1_op.
+ Definition w3_op := mk_zn2z_op w2_op.
+ Definition w4_op := mk_zn2z_op_karatsuba w3_op.
+ Definition w5_op := mk_zn2z_op_karatsuba w4_op.
+ Definition w6_op := mk_zn2z_op_karatsuba w5_op.
+ Definition w7_op := mk_zn2z_op_karatsuba w6_op.
+ Definition w8_op := mk_zn2z_op_karatsuba w7_op.
+ Definition w9_op := mk_zn2z_op_karatsuba w8_op.
+ Definition w10_op := mk_zn2z_op_karatsuba w9_op.
+ Definition w11_op := mk_zn2z_op_karatsuba w10_op.
+ Definition w12_op := mk_zn2z_op_karatsuba w11_op.
+ Definition w13_op := mk_zn2z_op_karatsuba w12_op.
+ Definition w14_op := mk_zn2z_op_karatsuba w13_op.
+ Definition w15_op := mk_zn2z_op_karatsuba w14_op.
+
+ Section Make_op.
+ Variable mk : forall w', znz_op w' -> znz_op (zn2z w').
+
+ Fixpoint make_op_aux (n:nat) : znz_op (word w12 (S n)):=
+ match n return znz_op (word w12 (S n)) with
+ | O => w13_op
+ | S n1 =>
+ match n1 return znz_op (word w12 (S (S n1))) with
+ | O => w14_op
+ | S n2 =>
+ match n2 return znz_op (word w12 (S (S (S n2)))) with
+ | O => w15_op
+ | S n3 => mk _ (mk _ (mk _ (make_op_aux n3)))
+ end
+ end
+ end.
+
+ End Make_op.
+
+ Definition make_op := make_op_aux mk_zn2z_op_karatsuba.
+
+ Inductive t_ : Set :=
+ | N0 : w0 -> t_
+ | N1 : w1 -> t_
+ | N2 : w2 -> t_
+ | N3 : w3 -> t_
+ | N4 : w4 -> t_
+ | N5 : w5 -> t_
+ | N6 : w6 -> t_
+ | N7 : w7 -> t_
+ | N8 : w8 -> t_
+ | N9 : w9 -> t_
+ | N10 : w10 -> t_
+ | N11 : w11 -> t_
+ | N12 : w12 -> t_
+ | Nn : forall n, word w12 (S n) -> t_.
+
+ Definition t := t_.
+
+ Definition w_0 := w0_op.(znz_0).
+
+ Definition one0 := w0_op.(znz_1).
+ Definition one1 := w1_op.(znz_1).
+ Definition one2 := w2_op.(znz_1).
+ Definition one3 := w3_op.(znz_1).
+ Definition one4 := w4_op.(znz_1).
+ Definition one5 := w5_op.(znz_1).
+ Definition one6 := w6_op.(znz_1).
+ Definition one7 := w7_op.(znz_1).
+ Definition one8 := w8_op.(znz_1).
+ Definition one9 := w9_op.(znz_1).
+ Definition one10 := w10_op.(znz_1).
+ Definition one11 := w11_op.(znz_1).
+ Definition one12 := w12_op.(znz_1).
+
+ Definition zero := N0 w_0.
+ Definition one := N0 one0.
+
+ Definition w0_succ_c := w0_op.(znz_succ_c).
+ Definition w1_succ_c := w1_op.(znz_succ_c).
+ Definition w2_succ_c := w2_op.(znz_succ_c).
+ Definition w3_succ_c := w3_op.(znz_succ_c).
+ Definition w4_succ_c := w4_op.(znz_succ_c).
+ Definition w5_succ_c := w5_op.(znz_succ_c).
+ Definition w6_succ_c := w6_op.(znz_succ_c).
+ Definition w7_succ_c := w7_op.(znz_succ_c).
+ Definition w8_succ_c := w8_op.(znz_succ_c).
+ Definition w9_succ_c := w9_op.(znz_succ_c).
+ Definition w10_succ_c := w10_op.(znz_succ_c).
+ Definition w11_succ_c := w11_op.(znz_succ_c).
+ Definition w12_succ_c := w12_op.(znz_succ_c).
+
+ Definition w0_succ := w0_op.(znz_succ).
+ Definition w1_succ := w1_op.(znz_succ).
+ Definition w2_succ := w2_op.(znz_succ).
+ Definition w3_succ := w3_op.(znz_succ).
+ Definition w4_succ := w4_op.(znz_succ).
+ Definition w5_succ := w5_op.(znz_succ).
+ Definition w6_succ := w6_op.(znz_succ).
+ Definition w7_succ := w7_op.(znz_succ).
+ Definition w8_succ := w8_op.(znz_succ).
+ Definition w9_succ := w9_op.(znz_succ).
+ Definition w10_succ := w10_op.(znz_succ).
+ Definition w11_succ := w11_op.(znz_succ).
+ Definition w12_succ := w12_op.(znz_succ).
+
+ Definition succ x :=
+ match x with
+ | N0 wx =>
+ match w0_succ_c wx with
+ | C0 r => N0 r
+ | C1 r => N1 (WW one0 r)
+ end
+ | N1 wx =>
+ match w1_succ_c wx with
+ | C0 r => N1 r
+ | C1 r => N2 (WW one1 r)
+ end
+ | N2 wx =>
+ match w2_succ_c wx with
+ | C0 r => N2 r
+ | C1 r => N3 (WW one2 r)
+ end
+ | N3 wx =>
+ match w3_succ_c wx with
+ | C0 r => N3 r
+ | C1 r => N4 (WW one3 r)
+ end
+ | N4 wx =>
+ match w4_succ_c wx with
+ | C0 r => N4 r
+ | C1 r => N5 (WW one4 r)
+ end
+ | N5 wx =>
+ match w5_succ_c wx with
+ | C0 r => N5 r
+ | C1 r => N6 (WW one5 r)
+ end
+ | N6 wx =>
+ match w6_succ_c wx with
+ | C0 r => N6 r
+ | C1 r => N7 (WW one6 r)
+ end
+ | N7 wx =>
+ match w7_succ_c wx with
+ | C0 r => N7 r
+ | C1 r => N8 (WW one7 r)
+ end
+ | N8 wx =>
+ match w8_succ_c wx with
+ | C0 r => N8 r
+ | C1 r => N9 (WW one8 r)
+ end
+ | N9 wx =>
+ match w9_succ_c wx with
+ | C0 r => N9 r
+ | C1 r => N10 (WW one9 r)
+ end
+ | N10 wx =>
+ match w10_succ_c wx with
+ | C0 r => N10 r
+ | C1 r => N11 (WW one10 r)
+ end
+ | N11 wx =>
+ match w11_succ_c wx with
+ | C0 r => N11 r
+ | C1 r => N12 (WW one11 r)
+ end
+ | N12 wx =>
+ match w12_succ_c wx with
+ | C0 r => N12 r
+ | C1 r => Nn 0 (WW one12 r)
+ end
+ | Nn n wx =>
+ let op := make_op n in
+ match op.(znz_succ_c) wx with
+ | C0 r => Nn n r
+ | C1 r => Nn (S n) (WW op.(znz_1) r)
+ end
+ end.
+
+ Definition extend1 :=
+ Eval lazy beta zeta iota delta [extend]in extend 1.
+ Definition extend2 :=
+ Eval lazy beta zeta iota delta [extend]in extend 2.
+ Definition extend3 :=
+ Eval lazy beta zeta iota delta [extend]in extend 3.
+ Definition extend4 :=
+ Eval lazy beta zeta iota delta [extend]in extend 4.
+ Definition extend5 :=
+ Eval lazy beta zeta iota delta [extend]in extend 5.
+ Definition extend6 :=
+ Eval lazy beta zeta iota delta [extend]in extend 6.
+ Definition extend7 :=
+ Eval lazy beta zeta iota delta [extend]in extend 7.
+ Definition extend8 :=
+ Eval lazy beta zeta iota delta [extend]in extend 8.
+ Definition extend9 :=
+ Eval lazy beta zeta iota delta [extend]in extend 9.
+ Definition extend10 :=
+ Eval lazy beta zeta iota delta [extend]in extend 10.
+ Definition extend11 :=
+ Eval lazy beta zeta iota delta [extend]in extend 11.
+ Definition extend12 :=
+ Eval lazy beta zeta iota delta [extend]in extend 12.
+
+ Definition w0_eq0 := w0_op.(znz_eq0).
+ Definition w1_eq0 := w1_op.(znz_eq0).
+ Definition w2_eq0 := w2_op.(znz_eq0).
+ Definition w3_eq0 := w3_op.(znz_eq0).
+ Definition w4_eq0 := w4_op.(znz_eq0).
+ Definition w5_eq0 := w5_op.(znz_eq0).
+ Definition w6_eq0 := w6_op.(znz_eq0).
+ Definition w7_eq0 := w7_op.(znz_eq0).
+ Definition w8_eq0 := w8_op.(znz_eq0).
+ Definition w9_eq0 := w9_op.(znz_eq0).
+ Definition w10_eq0 := w10_op.(znz_eq0).
+ Definition w11_eq0 := w11_op.(znz_eq0).
+ Definition w12_eq0 := w12_op.(znz_eq0).
+
+
+ Definition w0_add_c := w0_op.(znz_add_c).
+ Definition w1_add_c := w1_op.(znz_add_c).
+ Definition w2_add_c := w2_op.(znz_add_c).
+ Definition w3_add_c := w3_op.(znz_add_c).
+ Definition w4_add_c := w4_op.(znz_add_c).
+ Definition w5_add_c := w5_op.(znz_add_c).
+ Definition w6_add_c := w6_op.(znz_add_c).
+ Definition w7_add_c := w7_op.(znz_add_c).
+ Definition w8_add_c := w8_op.(znz_add_c).
+ Definition w9_add_c := w9_op.(znz_add_c).
+ Definition w10_add_c := w10_op.(znz_add_c).
+ Definition w11_add_c := w11_op.(znz_add_c).
+ Definition w12_add_c := w12_op.(znz_add_c).
+
+ Definition w0_add x y :=
+ match w0_add_c x y with
+ | C0 r => N0 r
+ | C1 r => N1 (WW one0 r)
+ end.
+ Definition w1_add x y :=
+ match w1_add_c x y with
+ | C0 r => N1 r
+ | C1 r => N2 (WW one1 r)
+ end.
+ Definition w2_add x y :=
+ match w2_add_c x y with
+ | C0 r => N2 r
+ | C1 r => N3 (WW one2 r)
+ end.
+ Definition w3_add x y :=
+ match w3_add_c x y with
+ | C0 r => N3 r
+ | C1 r => N4 (WW one3 r)
+ end.
+ Definition w4_add x y :=
+ match w4_add_c x y with
+ | C0 r => N4 r
+ | C1 r => N5 (WW one4 r)
+ end.
+ Definition w5_add x y :=
+ match w5_add_c x y with
+ | C0 r => N5 r
+ | C1 r => N6 (WW one5 r)
+ end.
+ Definition w6_add x y :=
+ match w6_add_c x y with
+ | C0 r => N6 r
+ | C1 r => N7 (WW one6 r)
+ end.
+ Definition w7_add x y :=
+ match w7_add_c x y with
+ | C0 r => N7 r
+ | C1 r => N8 (WW one7 r)
+ end.
+ Definition w8_add x y :=
+ match w8_add_c x y with
+ | C0 r => N8 r
+ | C1 r => N9 (WW one8 r)
+ end.
+ Definition w9_add x y :=
+ match w9_add_c x y with
+ | C0 r => N9 r
+ | C1 r => N10 (WW one9 r)
+ end.
+ Definition w10_add x y :=
+ match w10_add_c x y with
+ | C0 r => N10 r
+ | C1 r => N11 (WW one10 r)
+ end.
+ Definition w11_add x y :=
+ match w11_add_c x y with
+ | C0 r => N11 r
+ | C1 r => N12 (WW one11 r)
+ end.
+ Definition w12_add x y :=
+ match w12_add_c x y with
+ | C0 r => N12 r
+ | C1 r => Nn 0 (WW one12 r)
+ end.
+ Definition addn n (x y : word w12 (S n)) :=
+ let op := make_op n in
+ match op.(znz_add_c) x y with
+ | C0 r => Nn n r
+ | C1 r => Nn (S n) (WW op.(znz_1) r) end.
+
+ Definition add x y :=
+ match x, y with
+ | N0 wx, N0 wy => w0_add wx wy
+ | N0 wx, N1 wy =>
+ if w0_eq0 wx then y else w1_add (WW w_0 wx) wy
+ | N0 wx, N2 wy =>
+ if w0_eq0 wx then y else w2_add (extend1 w0 (WW w_0 wx)) wy
+ | N0 wx, N3 wy =>
+ if w0_eq0 wx then y else w3_add (extend2 w0 (WW w_0 wx)) wy
+ | N0 wx, N4 wy =>
+ if w0_eq0 wx then y else w4_add (extend3 w0 (WW w_0 wx)) wy
+ | N0 wx, N5 wy =>
+ if w0_eq0 wx then y else w5_add (extend4 w0 (WW w_0 wx)) wy
+ | N0 wx, N6 wy =>
+ if w0_eq0 wx then y else w6_add (extend5 w0 (WW w_0 wx)) wy
+ | N0 wx, N7 wy =>
+ if w0_eq0 wx then y else w7_add (extend6 w0 (WW w_0 wx)) wy
+ | N0 wx, N8 wy =>
+ if w0_eq0 wx then y else w8_add (extend7 w0 (WW w_0 wx)) wy
+ | N0 wx, N9 wy =>
+ if w0_eq0 wx then y else w9_add (extend8 w0 (WW w_0 wx)) wy
+ | N0 wx, N10 wy =>
+ if w0_eq0 wx then y else w10_add (extend9 w0 (WW w_0 wx)) wy
+ | N0 wx, N11 wy =>
+ if w0_eq0 wx then y else w11_add (extend10 w0 (WW w_0 wx)) wy
+ | N0 wx, N12 wy =>
+ if w0_eq0 wx then y else w12_add (extend11 w0 (WW w_0 wx)) wy
+ | N0 wx, Nn n wy =>
+ if w0_eq0 wx then y
+ else addn n (extend n w12 (extend12 w0 (WW w_0 wx))) wy
+ | N1 wx, N0 wy =>
+ if w0_eq0 wy then x else w1_add wx (WW w_0 wy)
+ | N1 wx, N1 wy => w1_add wx wy
+ | N1 wx, N2 wy => w2_add (extend1 w0 wx) wy
+ | N1 wx, N3 wy => w3_add (extend2 w0 wx) wy
+ | N1 wx, N4 wy => w4_add (extend3 w0 wx) wy
+ | N1 wx, N5 wy => w5_add (extend4 w0 wx) wy
+ | N1 wx, N6 wy => w6_add (extend5 w0 wx) wy
+ | N1 wx, N7 wy => w7_add (extend6 w0 wx) wy
+ | N1 wx, N8 wy => w8_add (extend7 w0 wx) wy
+ | N1 wx, N9 wy => w9_add (extend8 w0 wx) wy
+ | N1 wx, N10 wy => w10_add (extend9 w0 wx) wy
+ | N1 wx, N11 wy => w11_add (extend10 w0 wx) wy
+ | N1 wx, N12 wy => w12_add (extend11 w0 wx) wy
+ | N1 wx, Nn n wy => addn n (extend n w12 (extend12 w0 wx)) wy
+ | N2 wx, N0 wy =>
+ if w0_eq0 wy then x else w2_add wx (extend1 w0 (WW w_0 wy))
+ | N2 wx, N1 wy => w2_add wx (extend1 w0 wy)
+ | N2 wx, N2 wy => w2_add wx wy
+ | N2 wx, N3 wy => w3_add (extend1 w1 wx) wy
+ | N2 wx, N4 wy => w4_add (extend2 w1 wx) wy
+ | N2 wx, N5 wy => w5_add (extend3 w1 wx) wy
+ | N2 wx, N6 wy => w6_add (extend4 w1 wx) wy
+ | N2 wx, N7 wy => w7_add (extend5 w1 wx) wy
+ | N2 wx, N8 wy => w8_add (extend6 w1 wx) wy
+ | N2 wx, N9 wy => w9_add (extend7 w1 wx) wy
+ | N2 wx, N10 wy => w10_add (extend8 w1 wx) wy
+ | N2 wx, N11 wy => w11_add (extend9 w1 wx) wy
+ | N2 wx, N12 wy => w12_add (extend10 w1 wx) wy
+ | N2 wx, Nn n wy => addn n (extend n w12 (extend11 w1 wx)) wy
+ | N3 wx, N0 wy =>
+ if w0_eq0 wy then x else w3_add wx (extend2 w0 (WW w_0 wy))
+ | N3 wx, N1 wy => w3_add wx (extend2 w0 wy)
+ | N3 wx, N2 wy => w3_add wx (extend1 w1 wy)
+ | N3 wx, N3 wy => w3_add wx wy
+ | N3 wx, N4 wy => w4_add (extend1 w2 wx) wy
+ | N3 wx, N5 wy => w5_add (extend2 w2 wx) wy
+ | N3 wx, N6 wy => w6_add (extend3 w2 wx) wy
+ | N3 wx, N7 wy => w7_add (extend4 w2 wx) wy
+ | N3 wx, N8 wy => w8_add (extend5 w2 wx) wy
+ | N3 wx, N9 wy => w9_add (extend6 w2 wx) wy
+ | N3 wx, N10 wy => w10_add (extend7 w2 wx) wy
+ | N3 wx, N11 wy => w11_add (extend8 w2 wx) wy
+ | N3 wx, N12 wy => w12_add (extend9 w2 wx) wy
+ | N3 wx, Nn n wy => addn n (extend n w12 (extend10 w2 wx)) wy
+ | N4 wx, N0 wy =>
+ if w0_eq0 wy then x else w4_add wx (extend3 w0 (WW w_0 wy))
+ | N4 wx, N1 wy => w4_add wx (extend3 w0 wy)
+ | N4 wx, N2 wy => w4_add wx (extend2 w1 wy)
+ | N4 wx, N3 wy => w4_add wx (extend1 w2 wy)
+ | N4 wx, N4 wy => w4_add wx wy
+ | N4 wx, N5 wy => w5_add (extend1 w3 wx) wy
+ | N4 wx, N6 wy => w6_add (extend2 w3 wx) wy
+ | N4 wx, N7 wy => w7_add (extend3 w3 wx) wy
+ | N4 wx, N8 wy => w8_add (extend4 w3 wx) wy
+ | N4 wx, N9 wy => w9_add (extend5 w3 wx) wy
+ | N4 wx, N10 wy => w10_add (extend6 w3 wx) wy
+ | N4 wx, N11 wy => w11_add (extend7 w3 wx) wy
+ | N4 wx, N12 wy => w12_add (extend8 w3 wx) wy
+ | N4 wx, Nn n wy => addn n (extend n w12 (extend9 w3 wx)) wy
+ | N5 wx, N0 wy =>
+ if w0_eq0 wy then x else w5_add wx (extend4 w0 (WW w_0 wy))
+ | N5 wx, N1 wy => w5_add wx (extend4 w0 wy)
+ | N5 wx, N2 wy => w5_add wx (extend3 w1 wy)
+ | N5 wx, N3 wy => w5_add wx (extend2 w2 wy)
+ | N5 wx, N4 wy => w5_add wx (extend1 w3 wy)
+ | N5 wx, N5 wy => w5_add wx wy
+ | N5 wx, N6 wy => w6_add (extend1 w4 wx) wy
+ | N5 wx, N7 wy => w7_add (extend2 w4 wx) wy
+ | N5 wx, N8 wy => w8_add (extend3 w4 wx) wy
+ | N5 wx, N9 wy => w9_add (extend4 w4 wx) wy
+ | N5 wx, N10 wy => w10_add (extend5 w4 wx) wy
+ | N5 wx, N11 wy => w11_add (extend6 w4 wx) wy
+ | N5 wx, N12 wy => w12_add (extend7 w4 wx) wy
+ | N5 wx, Nn n wy => addn n (extend n w12 (extend8 w4 wx)) wy
+ | N6 wx, N0 wy =>
+ if w0_eq0 wy then x else w6_add wx (extend5 w0 (WW w_0 wy))
+ | N6 wx, N1 wy => w6_add wx (extend5 w0 wy)
+ | N6 wx, N2 wy => w6_add wx (extend4 w1 wy)
+ | N6 wx, N3 wy => w6_add wx (extend3 w2 wy)
+ | N6 wx, N4 wy => w6_add wx (extend2 w3 wy)
+ | N6 wx, N5 wy => w6_add wx (extend1 w4 wy)
+ | N6 wx, N6 wy => w6_add wx wy
+ | N6 wx, N7 wy => w7_add (extend1 w5 wx) wy
+ | N6 wx, N8 wy => w8_add (extend2 w5 wx) wy
+ | N6 wx, N9 wy => w9_add (extend3 w5 wx) wy
+ | N6 wx, N10 wy => w10_add (extend4 w5 wx) wy
+ | N6 wx, N11 wy => w11_add (extend5 w5 wx) wy
+ | N6 wx, N12 wy => w12_add (extend6 w5 wx) wy
+ | N6 wx, Nn n wy => addn n (extend n w12 (extend7 w5 wx)) wy
+ | N7 wx, N0 wy =>
+ if w0_eq0 wy then x else w7_add wx (extend6 w0 (WW w_0 wy))
+ | N7 wx, N1 wy => w7_add wx (extend6 w0 wy)
+ | N7 wx, N2 wy => w7_add wx (extend5 w1 wy)
+ | N7 wx, N3 wy => w7_add wx (extend4 w2 wy)
+ | N7 wx, N4 wy => w7_add wx (extend3 w3 wy)
+ | N7 wx, N5 wy => w7_add wx (extend2 w4 wy)
+ | N7 wx, N6 wy => w7_add wx (extend1 w5 wy)
+ | N7 wx, N7 wy => w7_add wx wy
+ | N7 wx, N8 wy => w8_add (extend1 w6 wx) wy
+ | N7 wx, N9 wy => w9_add (extend2 w6 wx) wy
+ | N7 wx, N10 wy => w10_add (extend3 w6 wx) wy
+ | N7 wx, N11 wy => w11_add (extend4 w6 wx) wy
+ | N7 wx, N12 wy => w12_add (extend5 w6 wx) wy
+ | N7 wx, Nn n wy => addn n (extend n w12 (extend6 w6 wx)) wy
+ | N8 wx, N0 wy =>
+ if w0_eq0 wy then x else w8_add wx (extend7 w0 (WW w_0 wy))
+ | N8 wx, N1 wy => w8_add wx (extend7 w0 wy)
+ | N8 wx, N2 wy => w8_add wx (extend6 w1 wy)
+ | N8 wx, N3 wy => w8_add wx (extend5 w2 wy)
+ | N8 wx, N4 wy => w8_add wx (extend4 w3 wy)
+ | N8 wx, N5 wy => w8_add wx (extend3 w4 wy)
+ | N8 wx, N6 wy => w8_add wx (extend2 w5 wy)
+ | N8 wx, N7 wy => w8_add wx (extend1 w6 wy)
+ | N8 wx, N8 wy => w8_add wx wy
+ | N8 wx, N9 wy => w9_add (extend1 w7 wx) wy
+ | N8 wx, N10 wy => w10_add (extend2 w7 wx) wy
+ | N8 wx, N11 wy => w11_add (extend3 w7 wx) wy
+ | N8 wx, N12 wy => w12_add (extend4 w7 wx) wy
+ | N8 wx, Nn n wy => addn n (extend n w12 (extend5 w7 wx)) wy
+ | N9 wx, N0 wy =>
+ if w0_eq0 wy then x else w9_add wx (extend8 w0 (WW w_0 wy))
+ | N9 wx, N1 wy => w9_add wx (extend8 w0 wy)
+ | N9 wx, N2 wy => w9_add wx (extend7 w1 wy)
+ | N9 wx, N3 wy => w9_add wx (extend6 w2 wy)
+ | N9 wx, N4 wy => w9_add wx (extend5 w3 wy)
+ | N9 wx, N5 wy => w9_add wx (extend4 w4 wy)
+ | N9 wx, N6 wy => w9_add wx (extend3 w5 wy)
+ | N9 wx, N7 wy => w9_add wx (extend2 w6 wy)
+ | N9 wx, N8 wy => w9_add wx (extend1 w7 wy)
+ | N9 wx, N9 wy => w9_add wx wy
+ | N9 wx, N10 wy => w10_add (extend1 w8 wx) wy
+ | N9 wx, N11 wy => w11_add (extend2 w8 wx) wy
+ | N9 wx, N12 wy => w12_add (extend3 w8 wx) wy
+ | N9 wx, Nn n wy => addn n (extend n w12 (extend4 w8 wx)) wy
+ | N10 wx, N0 wy =>
+ if w0_eq0 wy then x else w10_add wx (extend9 w0 (WW w_0 wy))
+ | N10 wx, N1 wy => w10_add wx (extend9 w0 wy)
+ | N10 wx, N2 wy => w10_add wx (extend8 w1 wy)
+ | N10 wx, N3 wy => w10_add wx (extend7 w2 wy)
+ | N10 wx, N4 wy => w10_add wx (extend6 w3 wy)
+ | N10 wx, N5 wy => w10_add wx (extend5 w4 wy)
+ | N10 wx, N6 wy => w10_add wx (extend4 w5 wy)
+ | N10 wx, N7 wy => w10_add wx (extend3 w6 wy)
+ | N10 wx, N8 wy => w10_add wx (extend2 w7 wy)
+ | N10 wx, N9 wy => w10_add wx (extend1 w8 wy)
+ | N10 wx, N10 wy => w10_add wx wy
+ | N10 wx, N11 wy => w11_add (extend1 w9 wx) wy
+ | N10 wx, N12 wy => w12_add (extend2 w9 wx) wy
+ | N10 wx, Nn n wy => addn n (extend n w12 (extend3 w9 wx)) wy
+ | N11 wx, N0 wy =>
+ if w0_eq0 wy then x else w11_add wx (extend10 w0 (WW w_0 wy))
+ | N11 wx, N1 wy => w11_add wx (extend10 w0 wy)
+ | N11 wx, N2 wy => w11_add wx (extend9 w1 wy)
+ | N11 wx, N3 wy => w11_add wx (extend8 w2 wy)
+ | N11 wx, N4 wy => w11_add wx (extend7 w3 wy)
+ | N11 wx, N5 wy => w11_add wx (extend6 w4 wy)
+ | N11 wx, N6 wy => w11_add wx (extend5 w5 wy)
+ | N11 wx, N7 wy => w11_add wx (extend4 w6 wy)
+ | N11 wx, N8 wy => w11_add wx (extend3 w7 wy)
+ | N11 wx, N9 wy => w11_add wx (extend2 w8 wy)
+ | N11 wx, N10 wy => w11_add wx (extend1 w9 wy)
+ | N11 wx, N11 wy => w11_add wx wy
+ | N11 wx, N12 wy => w12_add (extend1 w10 wx) wy
+ | N11 wx, Nn n wy => addn n (extend n w12 (extend2 w10 wx)) wy
+ | N12 wx, N0 wy =>
+ if w0_eq0 wy then x else w12_add wx (extend11 w0 (WW w_0 wy))
+ | N12 wx, N1 wy => w12_add wx (extend11 w0 wy)
+ | N12 wx, N2 wy => w12_add wx (extend10 w1 wy)
+ | N12 wx, N3 wy => w12_add wx (extend9 w2 wy)
+ | N12 wx, N4 wy => w12_add wx (extend8 w3 wy)
+ | N12 wx, N5 wy => w12_add wx (extend7 w4 wy)
+ | N12 wx, N6 wy => w12_add wx (extend6 w5 wy)
+ | N12 wx, N7 wy => w12_add wx (extend5 w6 wy)
+ | N12 wx, N8 wy => w12_add wx (extend4 w7 wy)
+ | N12 wx, N9 wy => w12_add wx (extend3 w8 wy)
+ | N12 wx, N10 wy => w12_add wx (extend2 w9 wy)
+ | N12 wx, N11 wy => w12_add wx (extend1 w10 wy)
+ | N12 wx, N12 wy => w12_add wx wy
+ | N12 wx, Nn n wy => addn n (extend n w12 (extend1 w11 wx)) wy
+ | Nn n wx, N0 wy =>
+ if w0_eq0 wy then x
+ else addn n wx (extend n w12 (extend12 w0 (WW w_0 wy)))
+ | Nn n wx, N1 wy => addn n wx (extend n w12 (extend12 w0 wy))
+ | Nn n wx, N2 wy => addn n wx (extend n w12 (extend11 w1 wy))
+ | Nn n wx, N3 wy => addn n wx (extend n w12 (extend10 w2 wy))
+ | Nn n wx, N4 wy => addn n wx (extend n w12 (extend9 w3 wy))
+ | Nn n wx, N5 wy => addn n wx (extend n w12 (extend8 w4 wy))
+ | Nn n wx, N6 wy => addn n wx (extend n w12 (extend7 w5 wy))
+ | Nn n wx, N7 wy => addn n wx (extend n w12 (extend6 w6 wy))
+ | Nn n wx, N8 wy => addn n wx (extend n w12 (extend5 w7 wy))
+ | Nn n wx, N9 wy => addn n wx (extend n w12 (extend4 w8 wy))
+ | Nn n wx, N10 wy => addn n wx (extend n w12 (extend3 w9 wy))
+ | Nn n wx, N11 wy => addn n wx (extend n w12 (extend2 w10 wy))
+ | Nn n wx, N12 wy => addn n wx (extend n w12 (extend1 w11 wy))
+ | Nn n wx, Nn m wy =>
+ match extend_to_max w12 n m wx wy with
+ | inl wx' => addn m wx' wy
+ | inr wy' => addn n wx wy'
+ end
+ end.
+
+ Definition reduce_0 (x:w) := N0 x.
+ Definition reduce_1 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w0_eq0 N0 N1.
+ Definition reduce_2 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w1_eq0 reduce_1 N2.
+ Definition reduce_3 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w2_eq0 reduce_2 N3.
+ Definition reduce_4 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w3_eq0 reduce_3 N4.
+ Definition reduce_5 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w4_eq0 reduce_4 N5.
+ Definition reduce_6 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w5_eq0 reduce_5 N6.
+ Definition reduce_7 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w6_eq0 reduce_6 N7.
+ Definition reduce_8 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w7_eq0 reduce_7 N8.
+ Definition reduce_9 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w8_eq0 reduce_8 N9.
+ Definition reduce_10 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w9_eq0 reduce_9 N10.
+ Definition reduce_11 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w10_eq0 reduce_10 N11.
+ Definition reduce_12 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w11_eq0 reduce_11 N12.
+ Definition reduce_13 :=
+ Eval lazy beta iota delta[reduce_n1] in
+ reduce_n1 _ _ zero w12_eq0 reduce_12 (Nn 0).
+ Definition reduce_n n :=
+ Eval lazy beta iota delta[reduce_n] in
+ reduce_n _ _ zero reduce_13 Nn n.
+
+ Definition w0_pred_c := w0_op.(znz_pred_c).
+ Definition w1_pred_c := w1_op.(znz_pred_c).
+ Definition w2_pred_c := w2_op.(znz_pred_c).
+ Definition w3_pred_c := w3_op.(znz_pred_c).
+ Definition w4_pred_c := w4_op.(znz_pred_c).
+ Definition w5_pred_c := w5_op.(znz_pred_c).
+ Definition w6_pred_c := w6_op.(znz_pred_c).
+ Definition w7_pred_c := w7_op.(znz_pred_c).
+ Definition w8_pred_c := w8_op.(znz_pred_c).
+ Definition w9_pred_c := w9_op.(znz_pred_c).
+ Definition w10_pred_c := w10_op.(znz_pred_c).
+ Definition w11_pred_c := w11_op.(znz_pred_c).
+ Definition w12_pred_c := w12_op.(znz_pred_c).
+
+ Definition pred x :=
+ match x with
+ | N0 wx =>
+ match w0_pred_c wx with
+ | C0 r => reduce_0 r
+ | C1 r => zero
+ end
+ | N1 wx =>
+ match w1_pred_c wx with
+ | C0 r => reduce_1 r
+ | C1 r => zero
+ end
+ | N2 wx =>
+ match w2_pred_c wx with
+ | C0 r => reduce_2 r
+ | C1 r => zero
+ end
+ | N3 wx =>
+ match w3_pred_c wx with
+ | C0 r => reduce_3 r
+ | C1 r => zero
+ end
+ | N4 wx =>
+ match w4_pred_c wx with
+ | C0 r => reduce_4 r
+ | C1 r => zero
+ end
+ | N5 wx =>
+ match w5_pred_c wx with
+ | C0 r => reduce_5 r
+ | C1 r => zero
+ end
+ | N6 wx =>
+ match w6_pred_c wx with
+ | C0 r => reduce_6 r
+ | C1 r => zero
+ end
+ | N7 wx =>
+ match w7_pred_c wx with
+ | C0 r => reduce_7 r
+ | C1 r => zero
+ end
+ | N8 wx =>
+ match w8_pred_c wx with
+ | C0 r => reduce_8 r
+ | C1 r => zero
+ end
+ | N9 wx =>
+ match w9_pred_c wx with
+ | C0 r => reduce_9 r
+ | C1 r => zero
+ end
+ | N10 wx =>
+ match w10_pred_c wx with
+ | C0 r => reduce_10 r
+ | C1 r => zero
+ end
+ | N11 wx =>
+ match w11_pred_c wx with
+ | C0 r => reduce_11 r
+ | C1 r => zero
+ end
+ | N12 wx =>
+ match w12_pred_c wx with
+ | C0 r => reduce_12 r
+ | C1 r => zero
+ end
+ | Nn n wx =>
+ let op := make_op n in
+ match op.(znz_pred_c) wx with
+ | C0 r => reduce_n n r
+ | C1 r => zero
+ end
+ end.
+
+
+ Definition w0_sub_c := w0_op.(znz_sub_c).
+ Definition w1_sub_c := w1_op.(znz_sub_c).
+ Definition w2_sub_c := w2_op.(znz_sub_c).
+ Definition w3_sub_c := w3_op.(znz_sub_c).
+ Definition w4_sub_c := w4_op.(znz_sub_c).
+ Definition w5_sub_c := w5_op.(znz_sub_c).
+ Definition w6_sub_c := w6_op.(znz_sub_c).
+ Definition w7_sub_c := w7_op.(znz_sub_c).
+ Definition w8_sub_c := w8_op.(znz_sub_c).
+ Definition w9_sub_c := w9_op.(znz_sub_c).
+ Definition w10_sub_c := w10_op.(znz_sub_c).
+ Definition w11_sub_c := w11_op.(znz_sub_c).
+ Definition w12_sub_c := w12_op.(znz_sub_c).
+
+ Definition w0_sub x y :=
+ match w0_sub_c x y with
+ | C0 r => reduce_0 r
+ | C1 r => zero
+ end.
+ Definition w1_sub x y :=
+ match w1_sub_c x y with
+ | C0 r => reduce_1 r
+ | C1 r => zero
+ end.
+ Definition w2_sub x y :=
+ match w2_sub_c x y with
+ | C0 r => reduce_2 r
+ | C1 r => zero
+ end.
+ Definition w3_sub x y :=
+ match w3_sub_c x y with
+ | C0 r => reduce_3 r
+ | C1 r => zero
+ end.
+ Definition w4_sub x y :=
+ match w4_sub_c x y with
+ | C0 r => reduce_4 r
+ | C1 r => zero
+ end.
+ Definition w5_sub x y :=
+ match w5_sub_c x y with
+ | C0 r => reduce_5 r
+ | C1 r => zero
+ end.
+ Definition w6_sub x y :=
+ match w6_sub_c x y with
+ | C0 r => reduce_6 r
+ | C1 r => zero
+ end.
+ Definition w7_sub x y :=
+ match w7_sub_c x y with
+ | C0 r => reduce_7 r
+ | C1 r => zero
+ end.
+ Definition w8_sub x y :=
+ match w8_sub_c x y with
+ | C0 r => reduce_8 r
+ | C1 r => zero
+ end.
+ Definition w9_sub x y :=
+ match w9_sub_c x y with
+ | C0 r => reduce_9 r
+ | C1 r => zero
+ end.
+ Definition w10_sub x y :=
+ match w10_sub_c x y with
+ | C0 r => reduce_10 r
+ | C1 r => zero
+ end.
+ Definition w11_sub x y :=
+ match w11_sub_c x y with
+ | C0 r => reduce_11 r
+ | C1 r => zero
+ end.
+ Definition w12_sub x y :=
+ match w12_sub_c x y with
+ | C0 r => reduce_12 r
+ | C1 r => zero
+ end.
+
+ Definition subn n (x y : word w12 (S n)) :=
+ let op := make_op n in
+ match op.(znz_sub_c) x y with
+ | C0 r => Nn n r
+ | C1 r => Nn (S n) (WW op.(znz_1) r) end.
+
+ Definition sub x y :=
+ match x, y with
+ | N0 wx, N0 wy => w0_sub wx wy
+ | N0 wx, N1 wy =>
+ if w0_eq0 wx then zero else w1_sub (WW w_0 wx) wy
+ | N0 wx, N2 wy =>
+ if w0_eq0 wx then zero else w2_sub (extend1 w0 (WW w_0 wx)) wy
+ | N0 wx, N3 wy =>
+ if w0_eq0 wx then zero else w3_sub (extend2 w0 (WW w_0 wx)) wy
+ | N0 wx, N4 wy =>
+ if w0_eq0 wx then zero else w4_sub (extend3 w0 (WW w_0 wx)) wy
+ | N0 wx, N5 wy =>
+ if w0_eq0 wx then zero else w5_sub (extend4 w0 (WW w_0 wx)) wy
+ | N0 wx, N6 wy =>
+ if w0_eq0 wx then zero else w6_sub (extend5 w0 (WW w_0 wx)) wy
+ | N0 wx, N7 wy =>
+ if w0_eq0 wx then zero else w7_sub (extend6 w0 (WW w_0 wx)) wy
+ | N0 wx, N8 wy =>
+ if w0_eq0 wx then zero else w8_sub (extend7 w0 (WW w_0 wx)) wy
+ | N0 wx, N9 wy =>
+ if w0_eq0 wx then zero else w9_sub (extend8 w0 (WW w_0 wx)) wy
+ | N0 wx, N10 wy =>
+ if w0_eq0 wx then zero else w10_sub (extend9 w0 (WW w_0 wx)) wy
+ | N0 wx, N11 wy =>
+ if w0_eq0 wx then zero else w11_sub (extend10 w0 (WW w_0 wx)) wy
+ | N0 wx, N12 wy =>
+ if w0_eq0 wx then zero else w12_sub (extend11 w0 (WW w_0 wx)) wy
+ | N0 wx, Nn n wy =>
+ if w0_eq0 wx then zero
+ else subn n (extend n w12 (extend12 w0 (WW w_0 wx))) wy
+ | N1 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w1_sub wx (WW w_0 wy)
+ | N1 wx, N1 wy => w1_sub wx wy
+ | N1 wx, N2 wy => w2_sub (extend1 w0 wx) wy
+ | N1 wx, N3 wy => w3_sub (extend2 w0 wx) wy
+ | N1 wx, N4 wy => w4_sub (extend3 w0 wx) wy
+ | N1 wx, N5 wy => w5_sub (extend4 w0 wx) wy
+ | N1 wx, N6 wy => w6_sub (extend5 w0 wx) wy
+ | N1 wx, N7 wy => w7_sub (extend6 w0 wx) wy
+ | N1 wx, N8 wy => w8_sub (extend7 w0 wx) wy
+ | N1 wx, N9 wy => w9_sub (extend8 w0 wx) wy
+ | N1 wx, N10 wy => w10_sub (extend9 w0 wx) wy
+ | N1 wx, N11 wy => w11_sub (extend10 w0 wx) wy
+ | N1 wx, N12 wy => w12_sub (extend11 w0 wx) wy
+ | N1 wx, Nn n wy => subn n (extend n w12 (extend12 w0 wx)) wy
+ | N2 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w2_sub wx (extend1 w0 (WW w_0 wy))
+ | N2 wx, N1 wy => w2_sub wx (extend1 w0 wy)
+ | N2 wx, N2 wy => w2_sub wx wy
+ | N2 wx, N3 wy => w3_sub (extend1 w1 wx) wy
+ | N2 wx, N4 wy => w4_sub (extend2 w1 wx) wy
+ | N2 wx, N5 wy => w5_sub (extend3 w1 wx) wy
+ | N2 wx, N6 wy => w6_sub (extend4 w1 wx) wy
+ | N2 wx, N7 wy => w7_sub (extend5 w1 wx) wy
+ | N2 wx, N8 wy => w8_sub (extend6 w1 wx) wy
+ | N2 wx, N9 wy => w9_sub (extend7 w1 wx) wy
+ | N2 wx, N10 wy => w10_sub (extend8 w1 wx) wy
+ | N2 wx, N11 wy => w11_sub (extend9 w1 wx) wy
+ | N2 wx, N12 wy => w12_sub (extend10 w1 wx) wy
+ | N2 wx, Nn n wy => subn n (extend n w12 (extend11 w1 wx)) wy
+ | N3 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w3_sub wx (extend2 w0 (WW w_0 wy))
+ | N3 wx, N1 wy => w3_sub wx (extend2 w0 wy)
+ | N3 wx, N2 wy => w3_sub wx (extend1 w1 wy)
+ | N3 wx, N3 wy => w3_sub wx wy
+ | N3 wx, N4 wy => w4_sub (extend1 w2 wx) wy
+ | N3 wx, N5 wy => w5_sub (extend2 w2 wx) wy
+ | N3 wx, N6 wy => w6_sub (extend3 w2 wx) wy
+ | N3 wx, N7 wy => w7_sub (extend4 w2 wx) wy
+ | N3 wx, N8 wy => w8_sub (extend5 w2 wx) wy
+ | N3 wx, N9 wy => w9_sub (extend6 w2 wx) wy
+ | N3 wx, N10 wy => w10_sub (extend7 w2 wx) wy
+ | N3 wx, N11 wy => w11_sub (extend8 w2 wx) wy
+ | N3 wx, N12 wy => w12_sub (extend9 w2 wx) wy
+ | N3 wx, Nn n wy => subn n (extend n w12 (extend10 w2 wx)) wy
+ | N4 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w4_sub wx (extend3 w0 (WW w_0 wy))
+ | N4 wx, N1 wy => w4_sub wx (extend3 w0 wy)
+ | N4 wx, N2 wy => w4_sub wx (extend2 w1 wy)
+ | N4 wx, N3 wy => w4_sub wx (extend1 w2 wy)
+ | N4 wx, N4 wy => w4_sub wx wy
+ | N4 wx, N5 wy => w5_sub (extend1 w3 wx) wy
+ | N4 wx, N6 wy => w6_sub (extend2 w3 wx) wy
+ | N4 wx, N7 wy => w7_sub (extend3 w3 wx) wy
+ | N4 wx, N8 wy => w8_sub (extend4 w3 wx) wy
+ | N4 wx, N9 wy => w9_sub (extend5 w3 wx) wy
+ | N4 wx, N10 wy => w10_sub (extend6 w3 wx) wy
+ | N4 wx, N11 wy => w11_sub (extend7 w3 wx) wy
+ | N4 wx, N12 wy => w12_sub (extend8 w3 wx) wy
+ | N4 wx, Nn n wy => subn n (extend n w12 (extend9 w3 wx)) wy
+ | N5 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w5_sub wx (extend4 w0 (WW w_0 wy))
+ | N5 wx, N1 wy => w5_sub wx (extend4 w0 wy)
+ | N5 wx, N2 wy => w5_sub wx (extend3 w1 wy)
+ | N5 wx, N3 wy => w5_sub wx (extend2 w2 wy)
+ | N5 wx, N4 wy => w5_sub wx (extend1 w3 wy)
+ | N5 wx, N5 wy => w5_sub wx wy
+ | N5 wx, N6 wy => w6_sub (extend1 w4 wx) wy
+ | N5 wx, N7 wy => w7_sub (extend2 w4 wx) wy
+ | N5 wx, N8 wy => w8_sub (extend3 w4 wx) wy
+ | N5 wx, N9 wy => w9_sub (extend4 w4 wx) wy
+ | N5 wx, N10 wy => w10_sub (extend5 w4 wx) wy
+ | N5 wx, N11 wy => w11_sub (extend6 w4 wx) wy
+ | N5 wx, N12 wy => w12_sub (extend7 w4 wx) wy
+ | N5 wx, Nn n wy => subn n (extend n w12 (extend8 w4 wx)) wy
+ | N6 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w6_sub wx (extend5 w0 (WW w_0 wy))
+ | N6 wx, N1 wy => w6_sub wx (extend5 w0 wy)
+ | N6 wx, N2 wy => w6_sub wx (extend4 w1 wy)
+ | N6 wx, N3 wy => w6_sub wx (extend3 w2 wy)
+ | N6 wx, N4 wy => w6_sub wx (extend2 w3 wy)
+ | N6 wx, N5 wy => w6_sub wx (extend1 w4 wy)
+ | N6 wx, N6 wy => w6_sub wx wy
+ | N6 wx, N7 wy => w7_sub (extend1 w5 wx) wy
+ | N6 wx, N8 wy => w8_sub (extend2 w5 wx) wy
+ | N6 wx, N9 wy => w9_sub (extend3 w5 wx) wy
+ | N6 wx, N10 wy => w10_sub (extend4 w5 wx) wy
+ | N6 wx, N11 wy => w11_sub (extend5 w5 wx) wy
+ | N6 wx, N12 wy => w12_sub (extend6 w5 wx) wy
+ | N6 wx, Nn n wy => subn n (extend n w12 (extend7 w5 wx)) wy
+ | N7 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w7_sub wx (extend6 w0 (WW w_0 wy))
+ | N7 wx, N1 wy => w7_sub wx (extend6 w0 wy)
+ | N7 wx, N2 wy => w7_sub wx (extend5 w1 wy)
+ | N7 wx, N3 wy => w7_sub wx (extend4 w2 wy)
+ | N7 wx, N4 wy => w7_sub wx (extend3 w3 wy)
+ | N7 wx, N5 wy => w7_sub wx (extend2 w4 wy)
+ | N7 wx, N6 wy => w7_sub wx (extend1 w5 wy)
+ | N7 wx, N7 wy => w7_sub wx wy
+ | N7 wx, N8 wy => w8_sub (extend1 w6 wx) wy
+ | N7 wx, N9 wy => w9_sub (extend2 w6 wx) wy
+ | N7 wx, N10 wy => w10_sub (extend3 w6 wx) wy
+ | N7 wx, N11 wy => w11_sub (extend4 w6 wx) wy
+ | N7 wx, N12 wy => w12_sub (extend5 w6 wx) wy
+ | N7 wx, Nn n wy => subn n (extend n w12 (extend6 w6 wx)) wy
+ | N8 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w8_sub wx (extend7 w0 (WW w_0 wy))
+ | N8 wx, N1 wy => w8_sub wx (extend7 w0 wy)
+ | N8 wx, N2 wy => w8_sub wx (extend6 w1 wy)
+ | N8 wx, N3 wy => w8_sub wx (extend5 w2 wy)
+ | N8 wx, N4 wy => w8_sub wx (extend4 w3 wy)
+ | N8 wx, N5 wy => w8_sub wx (extend3 w4 wy)
+ | N8 wx, N6 wy => w8_sub wx (extend2 w5 wy)
+ | N8 wx, N7 wy => w8_sub wx (extend1 w6 wy)
+ | N8 wx, N8 wy => w8_sub wx wy
+ | N8 wx, N9 wy => w9_sub (extend1 w7 wx) wy
+ | N8 wx, N10 wy => w10_sub (extend2 w7 wx) wy
+ | N8 wx, N11 wy => w11_sub (extend3 w7 wx) wy
+ | N8 wx, N12 wy => w12_sub (extend4 w7 wx) wy
+ | N8 wx, Nn n wy => subn n (extend n w12 (extend5 w7 wx)) wy
+ | N9 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w9_sub wx (extend8 w0 (WW w_0 wy))
+ | N9 wx, N1 wy => w9_sub wx (extend8 w0 wy)
+ | N9 wx, N2 wy => w9_sub wx (extend7 w1 wy)
+ | N9 wx, N3 wy => w9_sub wx (extend6 w2 wy)
+ | N9 wx, N4 wy => w9_sub wx (extend5 w3 wy)
+ | N9 wx, N5 wy => w9_sub wx (extend4 w4 wy)
+ | N9 wx, N6 wy => w9_sub wx (extend3 w5 wy)
+ | N9 wx, N7 wy => w9_sub wx (extend2 w6 wy)
+ | N9 wx, N8 wy => w9_sub wx (extend1 w7 wy)
+ | N9 wx, N9 wy => w9_sub wx wy
+ | N9 wx, N10 wy => w10_sub (extend1 w8 wx) wy
+ | N9 wx, N11 wy => w11_sub (extend2 w8 wx) wy
+ | N9 wx, N12 wy => w12_sub (extend3 w8 wx) wy
+ | N9 wx, Nn n wy => subn n (extend n w12 (extend4 w8 wx)) wy
+ | N10 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w10_sub wx (extend9 w0 (WW w_0 wy))
+ | N10 wx, N1 wy => w10_sub wx (extend9 w0 wy)
+ | N10 wx, N2 wy => w10_sub wx (extend8 w1 wy)
+ | N10 wx, N3 wy => w10_sub wx (extend7 w2 wy)
+ | N10 wx, N4 wy => w10_sub wx (extend6 w3 wy)
+ | N10 wx, N5 wy => w10_sub wx (extend5 w4 wy)
+ | N10 wx, N6 wy => w10_sub wx (extend4 w5 wy)
+ | N10 wx, N7 wy => w10_sub wx (extend3 w6 wy)
+ | N10 wx, N8 wy => w10_sub wx (extend2 w7 wy)
+ | N10 wx, N9 wy => w10_sub wx (extend1 w8 wy)
+ | N10 wx, N10 wy => w10_sub wx wy
+ | N10 wx, N11 wy => w11_sub (extend1 w9 wx) wy
+ | N10 wx, N12 wy => w12_sub (extend2 w9 wx) wy
+ | N10 wx, Nn n wy => subn n (extend n w12 (extend3 w9 wx)) wy
+ | N11 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w11_sub wx (extend10 w0 (WW w_0 wy))
+ | N11 wx, N1 wy => w11_sub wx (extend10 w0 wy)
+ | N11 wx, N2 wy => w11_sub wx (extend9 w1 wy)
+ | N11 wx, N3 wy => w11_sub wx (extend8 w2 wy)
+ | N11 wx, N4 wy => w11_sub wx (extend7 w3 wy)
+ | N11 wx, N5 wy => w11_sub wx (extend6 w4 wy)
+ | N11 wx, N6 wy => w11_sub wx (extend5 w5 wy)
+ | N11 wx, N7 wy => w11_sub wx (extend4 w6 wy)
+ | N11 wx, N8 wy => w11_sub wx (extend3 w7 wy)
+ | N11 wx, N9 wy => w11_sub wx (extend2 w8 wy)
+ | N11 wx, N10 wy => w11_sub wx (extend1 w9 wy)
+ | N11 wx, N11 wy => w11_sub wx wy
+ | N11 wx, N12 wy => w12_sub (extend1 w10 wx) wy
+ | N11 wx, Nn n wy => subn n (extend n w12 (extend2 w10 wx)) wy
+ | N12 wx, N0 wy =>
+ if w0_eq0 wy then x
+ else w12_sub wx (extend11 w0 (WW w_0 wy))
+ | N12 wx, N1 wy => w12_sub wx (extend11 w0 wy)
+ | N12 wx, N2 wy => w12_sub wx (extend10 w1 wy)
+ | N12 wx, N3 wy => w12_sub wx (extend9 w2 wy)
+ | N12 wx, N4 wy => w12_sub wx (extend8 w3 wy)
+ | N12 wx, N5 wy => w12_sub wx (extend7 w4 wy)
+ | N12 wx, N6 wy => w12_sub wx (extend6 w5 wy)
+ | N12 wx, N7 wy => w12_sub wx (extend5 w6 wy)
+ | N12 wx, N8 wy => w12_sub wx (extend4 w7 wy)
+ | N12 wx, N9 wy => w12_sub wx (extend3 w8 wy)
+ | N12 wx, N10 wy => w12_sub wx (extend2 w9 wy)
+ | N12 wx, N11 wy => w12_sub wx (extend1 w10 wy)
+ | N12 wx, N12 wy => w12_sub wx wy
+ | N12 wx, Nn n wy => subn n (extend n w12 (extend1 w11 wx)) wy
+ | Nn n wx, N0 wy =>
+ if w0_eq0 wy then x
+ else subn n wx (extend n w12 (extend12 w0 (WW w_0 wy)))
+ | Nn n wx, N1 wy => subn n wx (extend n w12 (extend12 w0 wy))
+ | Nn n wx, N2 wy => subn n wx (extend n w12 (extend11 w1 wy))
+ | Nn n wx, N3 wy => subn n wx (extend n w12 (extend10 w2 wy))
+ | Nn n wx, N4 wy => subn n wx (extend n w12 (extend9 w3 wy))
+ | Nn n wx, N5 wy => subn n wx (extend n w12 (extend8 w4 wy))
+ | Nn n wx, N6 wy => subn n wx (extend n w12 (extend7 w5 wy))
+ | Nn n wx, N7 wy => subn n wx (extend n w12 (extend6 w6 wy))
+ | Nn n wx, N8 wy => subn n wx (extend n w12 (extend5 w7 wy))
+ | Nn n wx, N9 wy => subn n wx (extend n w12 (extend4 w8 wy))
+ | Nn n wx, N10 wy => subn n wx (extend n w12 (extend3 w9 wy))
+ | Nn n wx, N11 wy => subn n wx (extend n w12 (extend2 w10 wy))
+ | Nn n wx, N12 wy => subn n wx (extend n w12 (extend1 w11 wy))
+ | Nn n wx, Nn m wy =>
+ match extend_to_max w12 n m wx wy with
+ | inl wx' => subn m wx' wy
+ | inr wy' => subn n wx wy'
+ end
+ end.
+
+ Definition compare_0 := w0_op.(znz_compare).
+ Definition comparen_0 :=
+ compare_mn_1 w0 w0 w_0 compare_0 (compare_0 w_0) compare_0.
+ Definition compare_1 := w1_op.(znz_compare).
+ Definition comparen_1 :=
+ compare_mn_1 w1 w1 W0 compare_1 (compare_1 W0) compare_1.
+ Definition compare_2 := w2_op.(znz_compare).
+ Definition comparen_2 :=
+ compare_mn_1 w2 w2 W0 compare_2 (compare_2 W0) compare_2.
+ Definition compare_3 := w3_op.(znz_compare).
+ Definition comparen_3 :=
+ compare_mn_1 w3 w3 W0 compare_3 (compare_3 W0) compare_3.
+ Definition compare_4 := w4_op.(znz_compare).
+ Definition comparen_4 :=
+ compare_mn_1 w4 w4 W0 compare_4 (compare_4 W0) compare_4.
+ Definition compare_5 := w5_op.(znz_compare).
+ Definition comparen_5 :=
+ compare_mn_1 w5 w5 W0 compare_5 (compare_5 W0) compare_5.
+ Definition compare_6 := w6_op.(znz_compare).
+ Definition comparen_6 :=
+ compare_mn_1 w6 w6 W0 compare_6 (compare_6 W0) compare_6.
+ Definition compare_7 := w7_op.(znz_compare).
+ Definition comparen_7 :=
+ compare_mn_1 w7 w7 W0 compare_7 (compare_7 W0) compare_7.
+ Definition compare_8 := w8_op.(znz_compare).
+ Definition comparen_8 :=
+ compare_mn_1 w8 w8 W0 compare_8 (compare_8 W0) compare_8.
+ Definition compare_9 := w9_op.(znz_compare).
+ Definition comparen_9 :=
+ compare_mn_1 w9 w9 W0 compare_9 (compare_9 W0) compare_9.
+ Definition compare_10 := w10_op.(znz_compare).
+ Definition comparen_10 :=
+ compare_mn_1 w10 w10 W0 compare_10 (compare_10 W0) compare_10.
+ Definition compare_11 := w11_op.(znz_compare).
+ Definition comparen_11 :=
+ compare_mn_1 w11 w11 W0 compare_11 (compare_11 W0) compare_11.
+ Definition compare_12 := w12_op.(znz_compare).
+ Definition comparen_12 :=
+ compare_mn_1 w12 w12 W0 compare_12 (compare_12 W0) compare_12.
+
+ Definition compare x y :=
+ match x, y with
+ | N0 wx, N0 wy => compare_0 wx wy
+ | N0 wx, N1 wy => opp_compare (comparen_0 1 wy wx)
+ | N0 wx, N2 wy => opp_compare (comparen_0 2 wy wx)
+ | N0 wx, N3 wy => opp_compare (comparen_0 3 wy wx)
+ | N0 wx, N4 wy => opp_compare (comparen_0 4 wy wx)
+ | N0 wx, N5 wy => opp_compare (comparen_0 5 wy wx)
+ | N0 wx, N6 wy => opp_compare (comparen_0 6 wy wx)
+ | N0 wx, N7 wy => opp_compare (comparen_0 7 wy wx)
+ | N0 wx, N8 wy => opp_compare (comparen_0 8 wy wx)
+ | N0 wx, N9 wy => opp_compare (comparen_0 9 wy wx)
+ | N0 wx, N10 wy => opp_compare (comparen_0 10 wy wx)
+ | N0 wx, N11 wy => opp_compare (comparen_0 11 wy wx)
+ | N0 wx, N12 wy => opp_compare (comparen_0 12 wy wx)
+ | N0 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w0 w_0 compare_0 (compare_12 W0) (comparen_0 12) (S n) wy wx)
+ | N1 wx, N0 wy => comparen_0 1 wx wy
+ | N1 wx, N1 wy => compare_1 wx wy
+ | N1 wx, N2 wy => opp_compare (comparen_1 1 wy wx)
+ | N1 wx, N3 wy => opp_compare (comparen_1 2 wy wx)
+ | N1 wx, N4 wy => opp_compare (comparen_1 3 wy wx)
+ | N1 wx, N5 wy => opp_compare (comparen_1 4 wy wx)
+ | N1 wx, N6 wy => opp_compare (comparen_1 5 wy wx)
+ | N1 wx, N7 wy => opp_compare (comparen_1 6 wy wx)
+ | N1 wx, N8 wy => opp_compare (comparen_1 7 wy wx)
+ | N1 wx, N9 wy => opp_compare (comparen_1 8 wy wx)
+ | N1 wx, N10 wy => opp_compare (comparen_1 9 wy wx)
+ | N1 wx, N11 wy => opp_compare (comparen_1 10 wy wx)
+ | N1 wx, N12 wy => opp_compare (comparen_1 11 wy wx)
+ | N1 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w1 W0 compare_1 (compare_12 W0) (comparen_1 11) (S n) wy wx)
+ | N2 wx, N0 wy => comparen_0 2 wx wy
+ | N2 wx, N1 wy => comparen_1 1 wx wy
+ | N2 wx, N2 wy => compare_2 wx wy
+ | N2 wx, N3 wy => opp_compare (comparen_2 1 wy wx)
+ | N2 wx, N4 wy => opp_compare (comparen_2 2 wy wx)
+ | N2 wx, N5 wy => opp_compare (comparen_2 3 wy wx)
+ | N2 wx, N6 wy => opp_compare (comparen_2 4 wy wx)
+ | N2 wx, N7 wy => opp_compare (comparen_2 5 wy wx)
+ | N2 wx, N8 wy => opp_compare (comparen_2 6 wy wx)
+ | N2 wx, N9 wy => opp_compare (comparen_2 7 wy wx)
+ | N2 wx, N10 wy => opp_compare (comparen_2 8 wy wx)
+ | N2 wx, N11 wy => opp_compare (comparen_2 9 wy wx)
+ | N2 wx, N12 wy => opp_compare (comparen_2 10 wy wx)
+ | N2 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w2 W0 compare_2 (compare_12 W0) (comparen_2 10) (S n) wy wx)
+ | N3 wx, N0 wy => comparen_0 3 wx wy
+ | N3 wx, N1 wy => comparen_1 2 wx wy
+ | N3 wx, N2 wy => comparen_2 1 wx wy
+ | N3 wx, N3 wy => compare_3 wx wy
+ | N3 wx, N4 wy => opp_compare (comparen_3 1 wy wx)
+ | N3 wx, N5 wy => opp_compare (comparen_3 2 wy wx)
+ | N3 wx, N6 wy => opp_compare (comparen_3 3 wy wx)
+ | N3 wx, N7 wy => opp_compare (comparen_3 4 wy wx)
+ | N3 wx, N8 wy => opp_compare (comparen_3 5 wy wx)
+ | N3 wx, N9 wy => opp_compare (comparen_3 6 wy wx)
+ | N3 wx, N10 wy => opp_compare (comparen_3 7 wy wx)
+ | N3 wx, N11 wy => opp_compare (comparen_3 8 wy wx)
+ | N3 wx, N12 wy => opp_compare (comparen_3 9 wy wx)
+ | N3 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w3 W0 compare_3 (compare_12 W0) (comparen_3 9) (S n) wy wx)
+ | N4 wx, N0 wy => comparen_0 4 wx wy
+ | N4 wx, N1 wy => comparen_1 3 wx wy
+ | N4 wx, N2 wy => comparen_2 2 wx wy
+ | N4 wx, N3 wy => comparen_3 1 wx wy
+ | N4 wx, N4 wy => compare_4 wx wy
+ | N4 wx, N5 wy => opp_compare (comparen_4 1 wy wx)
+ | N4 wx, N6 wy => opp_compare (comparen_4 2 wy wx)
+ | N4 wx, N7 wy => opp_compare (comparen_4 3 wy wx)
+ | N4 wx, N8 wy => opp_compare (comparen_4 4 wy wx)
+ | N4 wx, N9 wy => opp_compare (comparen_4 5 wy wx)
+ | N4 wx, N10 wy => opp_compare (comparen_4 6 wy wx)
+ | N4 wx, N11 wy => opp_compare (comparen_4 7 wy wx)
+ | N4 wx, N12 wy => opp_compare (comparen_4 8 wy wx)
+ | N4 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w4 W0 compare_4 (compare_12 W0) (comparen_4 8) (S n) wy wx)
+ | N5 wx, N0 wy => comparen_0 5 wx wy
+ | N5 wx, N1 wy => comparen_1 4 wx wy
+ | N5 wx, N2 wy => comparen_2 3 wx wy
+ | N5 wx, N3 wy => comparen_3 2 wx wy
+ | N5 wx, N4 wy => comparen_4 1 wx wy
+ | N5 wx, N5 wy => compare_5 wx wy
+ | N5 wx, N6 wy => opp_compare (comparen_5 1 wy wx)
+ | N5 wx, N7 wy => opp_compare (comparen_5 2 wy wx)
+ | N5 wx, N8 wy => opp_compare (comparen_5 3 wy wx)
+ | N5 wx, N9 wy => opp_compare (comparen_5 4 wy wx)
+ | N5 wx, N10 wy => opp_compare (comparen_5 5 wy wx)
+ | N5 wx, N11 wy => opp_compare (comparen_5 6 wy wx)
+ | N5 wx, N12 wy => opp_compare (comparen_5 7 wy wx)
+ | N5 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w5 W0 compare_5 (compare_12 W0) (comparen_5 7) (S n) wy wx)
+ | N6 wx, N0 wy => comparen_0 6 wx wy
+ | N6 wx, N1 wy => comparen_1 5 wx wy
+ | N6 wx, N2 wy => comparen_2 4 wx wy
+ | N6 wx, N3 wy => comparen_3 3 wx wy
+ | N6 wx, N4 wy => comparen_4 2 wx wy
+ | N6 wx, N5 wy => comparen_5 1 wx wy
+ | N6 wx, N6 wy => compare_6 wx wy
+ | N6 wx, N7 wy => opp_compare (comparen_6 1 wy wx)
+ | N6 wx, N8 wy => opp_compare (comparen_6 2 wy wx)
+ | N6 wx, N9 wy => opp_compare (comparen_6 3 wy wx)
+ | N6 wx, N10 wy => opp_compare (comparen_6 4 wy wx)
+ | N6 wx, N11 wy => opp_compare (comparen_6 5 wy wx)
+ | N6 wx, N12 wy => opp_compare (comparen_6 6 wy wx)
+ | N6 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w6 W0 compare_6 (compare_12 W0) (comparen_6 6) (S n) wy wx)
+ | N7 wx, N0 wy => comparen_0 7 wx wy
+ | N7 wx, N1 wy => comparen_1 6 wx wy
+ | N7 wx, N2 wy => comparen_2 5 wx wy
+ | N7 wx, N3 wy => comparen_3 4 wx wy
+ | N7 wx, N4 wy => comparen_4 3 wx wy
+ | N7 wx, N5 wy => comparen_5 2 wx wy
+ | N7 wx, N6 wy => comparen_6 1 wx wy
+ | N7 wx, N7 wy => compare_7 wx wy
+ | N7 wx, N8 wy => opp_compare (comparen_7 1 wy wx)
+ | N7 wx, N9 wy => opp_compare (comparen_7 2 wy wx)
+ | N7 wx, N10 wy => opp_compare (comparen_7 3 wy wx)
+ | N7 wx, N11 wy => opp_compare (comparen_7 4 wy wx)
+ | N7 wx, N12 wy => opp_compare (comparen_7 5 wy wx)
+ | N7 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w7 W0 compare_7 (compare_12 W0) (comparen_7 5) (S n) wy wx)
+ | N8 wx, N0 wy => comparen_0 8 wx wy
+ | N8 wx, N1 wy => comparen_1 7 wx wy
+ | N8 wx, N2 wy => comparen_2 6 wx wy
+ | N8 wx, N3 wy => comparen_3 5 wx wy
+ | N8 wx, N4 wy => comparen_4 4 wx wy
+ | N8 wx, N5 wy => comparen_5 3 wx wy
+ | N8 wx, N6 wy => comparen_6 2 wx wy
+ | N8 wx, N7 wy => comparen_7 1 wx wy
+ | N8 wx, N8 wy => compare_8 wx wy
+ | N8 wx, N9 wy => opp_compare (comparen_8 1 wy wx)
+ | N8 wx, N10 wy => opp_compare (comparen_8 2 wy wx)
+ | N8 wx, N11 wy => opp_compare (comparen_8 3 wy wx)
+ | N8 wx, N12 wy => opp_compare (comparen_8 4 wy wx)
+ | N8 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w8 W0 compare_8 (compare_12 W0) (comparen_8 4) (S n) wy wx)
+ | N9 wx, N0 wy => comparen_0 9 wx wy
+ | N9 wx, N1 wy => comparen_1 8 wx wy
+ | N9 wx, N2 wy => comparen_2 7 wx wy
+ | N9 wx, N3 wy => comparen_3 6 wx wy
+ | N9 wx, N4 wy => comparen_4 5 wx wy
+ | N9 wx, N5 wy => comparen_5 4 wx wy
+ | N9 wx, N6 wy => comparen_6 3 wx wy
+ | N9 wx, N7 wy => comparen_7 2 wx wy
+ | N9 wx, N8 wy => comparen_8 1 wx wy
+ | N9 wx, N9 wy => compare_9 wx wy
+ | N9 wx, N10 wy => opp_compare (comparen_9 1 wy wx)
+ | N9 wx, N11 wy => opp_compare (comparen_9 2 wy wx)
+ | N9 wx, N12 wy => opp_compare (comparen_9 3 wy wx)
+ | N9 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w9 W0 compare_9 (compare_12 W0) (comparen_9 3) (S n) wy wx)
+ | N10 wx, N0 wy => comparen_0 10 wx wy
+ | N10 wx, N1 wy => comparen_1 9 wx wy
+ | N10 wx, N2 wy => comparen_2 8 wx wy
+ | N10 wx, N3 wy => comparen_3 7 wx wy
+ | N10 wx, N4 wy => comparen_4 6 wx wy
+ | N10 wx, N5 wy => comparen_5 5 wx wy
+ | N10 wx, N6 wy => comparen_6 4 wx wy
+ | N10 wx, N7 wy => comparen_7 3 wx wy
+ | N10 wx, N8 wy => comparen_8 2 wx wy
+ | N10 wx, N9 wy => comparen_9 1 wx wy
+ | N10 wx, N10 wy => compare_10 wx wy
+ | N10 wx, N11 wy => opp_compare (comparen_10 1 wy wx)
+ | N10 wx, N12 wy => opp_compare (comparen_10 2 wy wx)
+ | N10 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w10 W0 compare_10 (compare_12 W0) (comparen_10 2) (S n) wy wx)
+ | N11 wx, N0 wy => comparen_0 11 wx wy
+ | N11 wx, N1 wy => comparen_1 10 wx wy
+ | N11 wx, N2 wy => comparen_2 9 wx wy
+ | N11 wx, N3 wy => comparen_3 8 wx wy
+ | N11 wx, N4 wy => comparen_4 7 wx wy
+ | N11 wx, N5 wy => comparen_5 6 wx wy
+ | N11 wx, N6 wy => comparen_6 5 wx wy
+ | N11 wx, N7 wy => comparen_7 4 wx wy
+ | N11 wx, N8 wy => comparen_8 3 wx wy
+ | N11 wx, N9 wy => comparen_9 2 wx wy
+ | N11 wx, N10 wy => comparen_10 1 wx wy
+ | N11 wx, N11 wy => compare_11 wx wy
+ | N11 wx, N12 wy => opp_compare (comparen_11 1 wy wx)
+ | N11 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w11 W0 compare_11 (compare_12 W0) (comparen_11 1) (S n) wy wx)
+ | N12 wx, N0 wy => comparen_0 12 wx wy
+ | N12 wx, N1 wy => comparen_1 11 wx wy
+ | N12 wx, N2 wy => comparen_2 10 wx wy
+ | N12 wx, N3 wy => comparen_3 9 wx wy
+ | N12 wx, N4 wy => comparen_4 8 wx wy
+ | N12 wx, N5 wy => comparen_5 7 wx wy
+ | N12 wx, N6 wy => comparen_6 6 wx wy
+ | N12 wx, N7 wy => comparen_7 5 wx wy
+ | N12 wx, N8 wy => comparen_8 4 wx wy
+ | N12 wx, N9 wy => comparen_9 3 wx wy
+ | N12 wx, N10 wy => comparen_10 2 wx wy
+ | N12 wx, N11 wy => comparen_11 1 wx wy
+ | N12 wx, N12 wy => compare_12 wx wy
+ | N12 wx, Nn n wy =>
+ opp_compare (compare_mn_1 w12 w12 W0 compare_12 (compare_12 W0) (comparen_12 0) (S n) wy wx)
+ | Nn n wx, N0 wy =>
+ compare_mn_1 w12 w0 w_0 compare_0 (compare_12 W0) (comparen_0 12) (S n) wx wy
+ | Nn n wx, N1 wy =>
+ compare_mn_1 w12 w1 W0 compare_1 (compare_12 W0) (comparen_1 11) (S n) wx wy
+ | Nn n wx, N2 wy =>
+ compare_mn_1 w12 w2 W0 compare_2 (compare_12 W0) (comparen_2 10) (S n) wx wy
+ | Nn n wx, N3 wy =>
+ compare_mn_1 w12 w3 W0 compare_3 (compare_12 W0) (comparen_3 9) (S n) wx wy
+ | Nn n wx, N4 wy =>
+ compare_mn_1 w12 w4 W0 compare_4 (compare_12 W0) (comparen_4 8) (S n) wx wy
+ | Nn n wx, N5 wy =>
+ compare_mn_1 w12 w5 W0 compare_5 (compare_12 W0) (comparen_5 7) (S n) wx wy
+ | Nn n wx, N6 wy =>
+ compare_mn_1 w12 w6 W0 compare_6 (compare_12 W0) (comparen_6 6) (S n) wx wy
+ | Nn n wx, N7 wy =>
+ compare_mn_1 w12 w7 W0 compare_7 (compare_12 W0) (comparen_7 5) (S n) wx wy
+ | Nn n wx, N8 wy =>
+ compare_mn_1 w12 w8 W0 compare_8 (compare_12 W0) (comparen_8 4) (S n) wx wy
+ | Nn n wx, N9 wy =>
+ compare_mn_1 w12 w9 W0 compare_9 (compare_12 W0) (comparen_9 3) (S n) wx wy
+ | Nn n wx, N10 wy =>
+ compare_mn_1 w12 w10 W0 compare_10 (compare_12 W0) (comparen_10 2) (S n) wx wy
+ | Nn n wx, N11 wy =>
+ compare_mn_1 w12 w11 W0 compare_11 (compare_12 W0) (comparen_11 1) (S n) wx wy
+ | Nn n wx, N12 wy =>
+ compare_mn_1 w12 w12 W0 compare_12 (compare_12 W0) (comparen_12 0) (S n) wx wy
+ | Nn n wx, Nn m wy =>
+ match extend_to_max w12 n m wx wy with
+ | inl wx' => let op := make_op m in op.(znz_compare) wx' wy
+ | inr wy' => let op := make_op n in op.(znz_compare) wx wy'
+ end
+ end.
+
+ Definition eq_bool x y :=
+ match compare x y with
+ | Eq => true
+ | _ => false
+ end.
+
+ Definition w0_mul_c := w0_op.(znz_mul_c).
+ Definition w1_mul_c := w1_op.(znz_mul_c).
+ Definition w2_mul_c := w2_op.(znz_mul_c).
+ Definition w3_mul_c := w3_op.(znz_mul_c).
+ Definition w4_mul_c := w4_op.(znz_mul_c).
+ Definition w5_mul_c := w5_op.(znz_mul_c).
+ Definition w6_mul_c := w6_op.(znz_mul_c).
+ Definition w7_mul_c := w7_op.(znz_mul_c).
+ Definition w8_mul_c := w8_op.(znz_mul_c).
+ Definition w9_mul_c := w9_op.(znz_mul_c).
+ Definition w10_mul_c := w10_op.(znz_mul_c).
+ Definition w11_mul_c := w11_op.(znz_mul_c).
+ Definition w12_mul_c := w12_op.(znz_mul_c).
+
+ Definition w0_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w0 w_0 w0_succ w0_add_c w0_mul_c.
+ Definition w1_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w1 W0 w1_succ w1_add_c w1_mul_c.
+ Definition w2_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w2 W0 w2_succ w2_add_c w2_mul_c.
+ Definition w3_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w3 W0 w3_succ w3_add_c w3_mul_c.
+ Definition w4_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w4 W0 w4_succ w4_add_c w4_mul_c.
+ Definition w5_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w5 W0 w5_succ w5_add_c w5_mul_c.
+ Definition w6_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w6 W0 w6_succ w6_add_c w6_mul_c.
+ Definition w7_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w7 W0 w7_succ w7_add_c w7_mul_c.
+ Definition w8_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w8 W0 w8_succ w8_add_c w8_mul_c.
+ Definition w9_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w9 W0 w9_succ w9_add_c w9_mul_c.
+ Definition w10_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w10 W0 w10_succ w10_add_c w10_mul_c.
+ Definition w11_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w11 W0 w11_succ w11_add_c w11_mul_c.
+ Definition w12_mul_add :=
+ Eval lazy beta delta [w_mul_add] in
+ @w_mul_add w12 W0 w12_succ w12_add_c w12_mul_c.
+
+ Definition w0_mul_add_n1 :=
+ @gen_mul_add_n1 w0 w_0 w0_op.(znz_WW) w0_op.(znz_0W) w0_mul_add.
+ Definition w1_mul_add_n1 :=
+ @gen_mul_add_n1 w1 W0 w1_op.(znz_WW) w1_op.(znz_0W) w1_mul_add.
+ Definition w2_mul_add_n1 :=
+ @gen_mul_add_n1 w2 W0 w2_op.(znz_WW) w2_op.(znz_0W) w2_mul_add.
+ Definition w3_mul_add_n1 :=
+ @gen_mul_add_n1 w3 W0 w3_op.(znz_WW) w3_op.(znz_0W) w3_mul_add.
+ Definition w4_mul_add_n1 :=
+ @gen_mul_add_n1 w4 W0 w4_op.(znz_WW) w4_op.(znz_0W) w4_mul_add.
+ Definition w5_mul_add_n1 :=
+ @gen_mul_add_n1 w5 W0 w5_op.(znz_WW) w5_op.(znz_0W) w5_mul_add.
+ Definition w6_mul_add_n1 :=
+ @gen_mul_add_n1 w6 W0 w6_op.(znz_WW) w6_op.(znz_0W) w6_mul_add.
+ Definition w7_mul_add_n1 :=
+ @gen_mul_add_n1 w7 W0 w7_op.(znz_WW) w7_op.(znz_0W) w7_mul_add.
+ Definition w8_mul_add_n1 :=
+ @gen_mul_add_n1 w8 W0 w8_op.(znz_WW) w8_op.(znz_0W) w8_mul_add.
+ Definition w9_mul_add_n1 :=
+ @gen_mul_add_n1 w9 W0 w9_op.(znz_WW) w9_op.(znz_0W) w9_mul_add.
+ Definition w10_mul_add_n1 :=
+ @gen_mul_add_n1 w10 W0 w10_op.(znz_WW) w10_op.(znz_0W) w10_mul_add.
+ Definition w11_mul_add_n1 :=
+ @gen_mul_add_n1 w11 W0 w11_op.(znz_WW) w11_op.(znz_0W) w11_mul_add.
+ Definition w12_mul_add_n1 :=
+ @gen_mul_add_n1 w12 W0 w12_op.(znz_WW) w12_op.(znz_0W) w12_mul_add.
+
+ Definition mul x y :=
+ match x, y with
+ | N0 wx, N0 wy =>
+ reduce_1 (w0_mul_c wx wy)
+ | N0 wx, N1 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 1 wy wx w_0 in
+ if w0_eq0 w then N1 r
+ else N2 (WW (WW w_0 w) r)
+ | N0 wx, N2 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 2 wy wx w_0 in
+ if w0_eq0 w then N2 r
+ else N3 (WW (extend1 w0 (WW w_0 w)) r)
+ | N0 wx, N3 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 3 wy wx w_0 in
+ if w0_eq0 w then N3 r
+ else N4 (WW (extend2 w0 (WW w_0 w)) r)
+ | N0 wx, N4 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 4 wy wx w_0 in
+ if w0_eq0 w then N4 r
+ else N5 (WW (extend3 w0 (WW w_0 w)) r)
+ | N0 wx, N5 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 5 wy wx w_0 in
+ if w0_eq0 w then N5 r
+ else N6 (WW (extend4 w0 (WW w_0 w)) r)
+ | N0 wx, N6 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 6 wy wx w_0 in
+ if w0_eq0 w then N6 r
+ else N7 (WW (extend5 w0 (WW w_0 w)) r)
+ | N0 wx, N7 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 7 wy wx w_0 in
+ if w0_eq0 w then N7 r
+ else N8 (WW (extend6 w0 (WW w_0 w)) r)
+ | N0 wx, N8 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 8 wy wx w_0 in
+ if w0_eq0 w then N8 r
+ else N9 (WW (extend7 w0 (WW w_0 w)) r)
+ | N0 wx, N9 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 9 wy wx w_0 in
+ if w0_eq0 w then N9 r
+ else N10 (WW (extend8 w0 (WW w_0 w)) r)
+ | N0 wx, N10 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 10 wy wx w_0 in
+ if w0_eq0 w then N10 r
+ else N11 (WW (extend9 w0 (WW w_0 w)) r)
+ | N0 wx, N11 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 11 wy wx w_0 in
+ if w0_eq0 w then N11 r
+ else N12 (WW (extend10 w0 (WW w_0 w)) r)
+ | N0 wx, N12 wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) := w0_mul_add_n1 12 wy wx w_0 in
+ if w0_eq0 w then N12 r
+ else Nn 0 (WW (extend11 w0 (WW w_0 w)) r)
+ | N0 wx, Nn n wy =>
+ if w0_eq0 wx then zero
+ else
+ let (w,r) :=
+ gen_mul_add_mn1 w_0 (fun r => extend11 w0 (WW w_0 r))
+ w12_op.(znz_0W) w12_op.(znz_WW)
+ (w0_mul_add_n1 12) (S n) wy wx w_0 in
+ if w0_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (extend12 w0 (WW w_0 w))) r)
+ | N1 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 1 wx wy w_0 in
+ if w0_eq0 w then N1 r
+ else N2 (WW (WW w_0 w) r)
+ | N1 wx, N1 wy =>
+ N2 (w1_mul_c wx wy)
+ | N1 wx, N2 wy =>
+ let (w,r) := w1_mul_add_n1 1 wy wx W0 in
+ if w1_eq0 w then N2 r
+ else N3 (WW (extend1 w0 w) r)
+ | N1 wx, N3 wy =>
+ let (w,r) := w1_mul_add_n1 2 wy wx W0 in
+ if w1_eq0 w then N3 r
+ else N4 (WW (extend2 w0 w) r)
+ | N1 wx, N4 wy =>
+ let (w,r) := w1_mul_add_n1 3 wy wx W0 in
+ if w1_eq0 w then N4 r
+ else N5 (WW (extend3 w0 w) r)
+ | N1 wx, N5 wy =>
+ let (w,r) := w1_mul_add_n1 4 wy wx W0 in
+ if w1_eq0 w then N5 r
+ else N6 (WW (extend4 w0 w) r)
+ | N1 wx, N6 wy =>
+ let (w,r) := w1_mul_add_n1 5 wy wx W0 in
+ if w1_eq0 w then N6 r
+ else N7 (WW (extend5 w0 w) r)
+ | N1 wx, N7 wy =>
+ let (w,r) := w1_mul_add_n1 6 wy wx W0 in
+ if w1_eq0 w then N7 r
+ else N8 (WW (extend6 w0 w) r)
+ | N1 wx, N8 wy =>
+ let (w,r) := w1_mul_add_n1 7 wy wx W0 in
+ if w1_eq0 w then N8 r
+ else N9 (WW (extend7 w0 w) r)
+ | N1 wx, N9 wy =>
+ let (w,r) := w1_mul_add_n1 8 wy wx W0 in
+ if w1_eq0 w then N9 r
+ else N10 (WW (extend8 w0 w) r)
+ | N1 wx, N10 wy =>
+ let (w,r) := w1_mul_add_n1 9 wy wx W0 in
+ if w1_eq0 w then N10 r
+ else N11 (WW (extend9 w0 w) r)
+ | N1 wx, N11 wy =>
+ let (w,r) := w1_mul_add_n1 10 wy wx W0 in
+ if w1_eq0 w then N11 r
+ else N12 (WW (extend10 w0 w) r)
+ | N1 wx, N12 wy =>
+ let (w,r) := w1_mul_add_n1 11 wy wx W0 in
+ if w1_eq0 w then N12 r
+ else Nn 0 (WW (extend11 w0 w) r)
+ | N1 wx, Nn n wy =>
+ let (w,r) :=
+ gen_mul_add_mn1 W0 (fun r => extend11 w0 r)
+ w12_op.(znz_0W) w12_op.(znz_WW)
+ (w1_mul_add_n1 11) (S n) wy wx W0 in
+ if w1_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (extend12 w0 w)) r)
+ | N2 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 2 wx wy w_0 in
+ if w0_eq0 w then N2 r
+ else N3 (WW (extend1 w0 (WW w_0 w)) r)
+ | N2 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 1 wx wy W0 in
+ if w1_eq0 w then N2 r
+ else N3 (WW (extend1 w0 w) r)
+ | N2 wx, N2 wy =>
+ N3 (w2_mul_c wx wy)
+ | N2 wx, N3 wy =>
+ let (w,r) := w2_mul_add_n1 1 wy wx W0 in
+ if w2_eq0 w then N3 r
+ else N4 (WW (extend1 w1 w) r)
+ | N2 wx, N4 wy =>
+ let (w,r) := w2_mul_add_n1 2 wy wx W0 in
+ if w2_eq0 w then N4 r
+ else N5 (WW (extend2 w1 w) r)
+ | N2 wx, N5 wy =>
+ let (w,r) := w2_mul_add_n1 3 wy wx W0 in
+ if w2_eq0 w then N5 r
+ else N6 (WW (extend3 w1 w) r)
+ | N2 wx, N6 wy =>
+ let (w,r) := w2_mul_add_n1 4 wy wx W0 in
+ if w2_eq0 w then N6 r
+ else N7 (WW (extend4 w1 w) r)
+ | N2 wx, N7 wy =>
+ let (w,r) := w2_mul_add_n1 5 wy wx W0 in
+ if w2_eq0 w then N7 r
+ else N8 (WW (extend5 w1 w) r)
+ | N2 wx, N8 wy =>
+ let (w,r) := w2_mul_add_n1 6 wy wx W0 in
+ if w2_eq0 w then N8 r
+ else N9 (WW (extend6 w1 w) r)
+ | N2 wx, N9 wy =>
+ let (w,r) := w2_mul_add_n1 7 wy wx W0 in
+ if w2_eq0 w then N9 r
+ else N10 (WW (extend7 w1 w) r)
+ | N2 wx, N10 wy =>
+ let (w,r) := w2_mul_add_n1 8 wy wx W0 in
+ if w2_eq0 w then N10 r
+ else N11 (WW (extend8 w1 w) r)
+ | N2 wx, N11 wy =>
+ let (w,r) := w2_mul_add_n1 9 wy wx W0 in
+ if w2_eq0 w then N11 r
+ else N12 (WW (extend9 w1 w) r)
+ | N2 wx, N12 wy =>
+ let (w,r) := w2_mul_add_n1 10 wy wx W0 in
+ if w2_eq0 w then N12 r
+ else Nn 0 (WW (extend10 w1 w) r)
+ | N2 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend10 w1 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N3 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 3 wx wy w_0 in
+ if w0_eq0 w then N3 r
+ else N4 (WW (extend2 w0 (WW w_0 w)) r)
+ | N3 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 2 wx wy W0 in
+ if w1_eq0 w then N3 r
+ else N4 (WW (extend2 w0 w) r)
+ | N3 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 1 wx wy W0 in
+ if w2_eq0 w then N3 r
+ else N4 (WW (extend1 w1 w) r)
+ | N3 wx, N3 wy =>
+ N4 (w3_mul_c wx wy)
+ | N3 wx, N4 wy =>
+ let (w,r) := w3_mul_add_n1 1 wy wx W0 in
+ if w3_eq0 w then N4 r
+ else N5 (WW (extend1 w2 w) r)
+ | N3 wx, N5 wy =>
+ let (w,r) := w3_mul_add_n1 2 wy wx W0 in
+ if w3_eq0 w then N5 r
+ else N6 (WW (extend2 w2 w) r)
+ | N3 wx, N6 wy =>
+ let (w,r) := w3_mul_add_n1 3 wy wx W0 in
+ if w3_eq0 w then N6 r
+ else N7 (WW (extend3 w2 w) r)
+ | N3 wx, N7 wy =>
+ let (w,r) := w3_mul_add_n1 4 wy wx W0 in
+ if w3_eq0 w then N7 r
+ else N8 (WW (extend4 w2 w) r)
+ | N3 wx, N8 wy =>
+ let (w,r) := w3_mul_add_n1 5 wy wx W0 in
+ if w3_eq0 w then N8 r
+ else N9 (WW (extend5 w2 w) r)
+ | N3 wx, N9 wy =>
+ let (w,r) := w3_mul_add_n1 6 wy wx W0 in
+ if w3_eq0 w then N9 r
+ else N10 (WW (extend6 w2 w) r)
+ | N3 wx, N10 wy =>
+ let (w,r) := w3_mul_add_n1 7 wy wx W0 in
+ if w3_eq0 w then N10 r
+ else N11 (WW (extend7 w2 w) r)
+ | N3 wx, N11 wy =>
+ let (w,r) := w3_mul_add_n1 8 wy wx W0 in
+ if w3_eq0 w then N11 r
+ else N12 (WW (extend8 w2 w) r)
+ | N3 wx, N12 wy =>
+ let (w,r) := w3_mul_add_n1 9 wy wx W0 in
+ if w3_eq0 w then N12 r
+ else Nn 0 (WW (extend9 w2 w) r)
+ | N3 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend9 w2 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N4 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 4 wx wy w_0 in
+ if w0_eq0 w then N4 r
+ else N5 (WW (extend3 w0 (WW w_0 w)) r)
+ | N4 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 3 wx wy W0 in
+ if w1_eq0 w then N4 r
+ else N5 (WW (extend3 w0 w) r)
+ | N4 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 2 wx wy W0 in
+ if w2_eq0 w then N4 r
+ else N5 (WW (extend2 w1 w) r)
+ | N4 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 1 wx wy W0 in
+ if w3_eq0 w then N4 r
+ else N5 (WW (extend1 w2 w) r)
+ | N4 wx, N4 wy =>
+ N5 (w4_mul_c wx wy)
+ | N4 wx, N5 wy =>
+ let (w,r) := w4_mul_add_n1 1 wy wx W0 in
+ if w4_eq0 w then N5 r
+ else N6 (WW (extend1 w3 w) r)
+ | N4 wx, N6 wy =>
+ let (w,r) := w4_mul_add_n1 2 wy wx W0 in
+ if w4_eq0 w then N6 r
+ else N7 (WW (extend2 w3 w) r)
+ | N4 wx, N7 wy =>
+ let (w,r) := w4_mul_add_n1 3 wy wx W0 in
+ if w4_eq0 w then N7 r
+ else N8 (WW (extend3 w3 w) r)
+ | N4 wx, N8 wy =>
+ let (w,r) := w4_mul_add_n1 4 wy wx W0 in
+ if w4_eq0 w then N8 r
+ else N9 (WW (extend4 w3 w) r)
+ | N4 wx, N9 wy =>
+ let (w,r) := w4_mul_add_n1 5 wy wx W0 in
+ if w4_eq0 w then N9 r
+ else N10 (WW (extend5 w3 w) r)
+ | N4 wx, N10 wy =>
+ let (w,r) := w4_mul_add_n1 6 wy wx W0 in
+ if w4_eq0 w then N10 r
+ else N11 (WW (extend6 w3 w) r)
+ | N4 wx, N11 wy =>
+ let (w,r) := w4_mul_add_n1 7 wy wx W0 in
+ if w4_eq0 w then N11 r
+ else N12 (WW (extend7 w3 w) r)
+ | N4 wx, N12 wy =>
+ let (w,r) := w4_mul_add_n1 8 wy wx W0 in
+ if w4_eq0 w then N12 r
+ else Nn 0 (WW (extend8 w3 w) r)
+ | N4 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend8 w3 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N5 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 5 wx wy w_0 in
+ if w0_eq0 w then N5 r
+ else N6 (WW (extend4 w0 (WW w_0 w)) r)
+ | N5 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 4 wx wy W0 in
+ if w1_eq0 w then N5 r
+ else N6 (WW (extend4 w0 w) r)
+ | N5 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 3 wx wy W0 in
+ if w2_eq0 w then N5 r
+ else N6 (WW (extend3 w1 w) r)
+ | N5 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 2 wx wy W0 in
+ if w3_eq0 w then N5 r
+ else N6 (WW (extend2 w2 w) r)
+ | N5 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 1 wx wy W0 in
+ if w4_eq0 w then N5 r
+ else N6 (WW (extend1 w3 w) r)
+ | N5 wx, N5 wy =>
+ N6 (w5_mul_c wx wy)
+ | N5 wx, N6 wy =>
+ let (w,r) := w5_mul_add_n1 1 wy wx W0 in
+ if w5_eq0 w then N6 r
+ else N7 (WW (extend1 w4 w) r)
+ | N5 wx, N7 wy =>
+ let (w,r) := w5_mul_add_n1 2 wy wx W0 in
+ if w5_eq0 w then N7 r
+ else N8 (WW (extend2 w4 w) r)
+ | N5 wx, N8 wy =>
+ let (w,r) := w5_mul_add_n1 3 wy wx W0 in
+ if w5_eq0 w then N8 r
+ else N9 (WW (extend3 w4 w) r)
+ | N5 wx, N9 wy =>
+ let (w,r) := w5_mul_add_n1 4 wy wx W0 in
+ if w5_eq0 w then N9 r
+ else N10 (WW (extend4 w4 w) r)
+ | N5 wx, N10 wy =>
+ let (w,r) := w5_mul_add_n1 5 wy wx W0 in
+ if w5_eq0 w then N10 r
+ else N11 (WW (extend5 w4 w) r)
+ | N5 wx, N11 wy =>
+ let (w,r) := w5_mul_add_n1 6 wy wx W0 in
+ if w5_eq0 w then N11 r
+ else N12 (WW (extend6 w4 w) r)
+ | N5 wx, N12 wy =>
+ let (w,r) := w5_mul_add_n1 7 wy wx W0 in
+ if w5_eq0 w then N12 r
+ else Nn 0 (WW (extend7 w4 w) r)
+ | N5 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend7 w4 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N6 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 6 wx wy w_0 in
+ if w0_eq0 w then N6 r
+ else N7 (WW (extend5 w0 (WW w_0 w)) r)
+ | N6 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 5 wx wy W0 in
+ if w1_eq0 w then N6 r
+ else N7 (WW (extend5 w0 w) r)
+ | N6 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 4 wx wy W0 in
+ if w2_eq0 w then N6 r
+ else N7 (WW (extend4 w1 w) r)
+ | N6 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 3 wx wy W0 in
+ if w3_eq0 w then N6 r
+ else N7 (WW (extend3 w2 w) r)
+ | N6 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 2 wx wy W0 in
+ if w4_eq0 w then N6 r
+ else N7 (WW (extend2 w3 w) r)
+ | N6 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 1 wx wy W0 in
+ if w5_eq0 w then N6 r
+ else N7 (WW (extend1 w4 w) r)
+ | N6 wx, N6 wy =>
+ N7 (w6_mul_c wx wy)
+ | N6 wx, N7 wy =>
+ let (w,r) := w6_mul_add_n1 1 wy wx W0 in
+ if w6_eq0 w then N7 r
+ else N8 (WW (extend1 w5 w) r)
+ | N6 wx, N8 wy =>
+ let (w,r) := w6_mul_add_n1 2 wy wx W0 in
+ if w6_eq0 w then N8 r
+ else N9 (WW (extend2 w5 w) r)
+ | N6 wx, N9 wy =>
+ let (w,r) := w6_mul_add_n1 3 wy wx W0 in
+ if w6_eq0 w then N9 r
+ else N10 (WW (extend3 w5 w) r)
+ | N6 wx, N10 wy =>
+ let (w,r) := w6_mul_add_n1 4 wy wx W0 in
+ if w6_eq0 w then N10 r
+ else N11 (WW (extend4 w5 w) r)
+ | N6 wx, N11 wy =>
+ let (w,r) := w6_mul_add_n1 5 wy wx W0 in
+ if w6_eq0 w then N11 r
+ else N12 (WW (extend5 w5 w) r)
+ | N6 wx, N12 wy =>
+ let (w,r) := w6_mul_add_n1 6 wy wx W0 in
+ if w6_eq0 w then N12 r
+ else Nn 0 (WW (extend6 w5 w) r)
+ | N6 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend6 w5 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N7 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 7 wx wy w_0 in
+ if w0_eq0 w then N7 r
+ else N8 (WW (extend6 w0 (WW w_0 w)) r)
+ | N7 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 6 wx wy W0 in
+ if w1_eq0 w then N7 r
+ else N8 (WW (extend6 w0 w) r)
+ | N7 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 5 wx wy W0 in
+ if w2_eq0 w then N7 r
+ else N8 (WW (extend5 w1 w) r)
+ | N7 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 4 wx wy W0 in
+ if w3_eq0 w then N7 r
+ else N8 (WW (extend4 w2 w) r)
+ | N7 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 3 wx wy W0 in
+ if w4_eq0 w then N7 r
+ else N8 (WW (extend3 w3 w) r)
+ | N7 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 2 wx wy W0 in
+ if w5_eq0 w then N7 r
+ else N8 (WW (extend2 w4 w) r)
+ | N7 wx, N6 wy =>
+ let (w,r) := w6_mul_add_n1 1 wx wy W0 in
+ if w6_eq0 w then N7 r
+ else N8 (WW (extend1 w5 w) r)
+ | N7 wx, N7 wy =>
+ N8 (w7_mul_c wx wy)
+ | N7 wx, N8 wy =>
+ let (w,r) := w7_mul_add_n1 1 wy wx W0 in
+ if w7_eq0 w then N8 r
+ else N9 (WW (extend1 w6 w) r)
+ | N7 wx, N9 wy =>
+ let (w,r) := w7_mul_add_n1 2 wy wx W0 in
+ if w7_eq0 w then N9 r
+ else N10 (WW (extend2 w6 w) r)
+ | N7 wx, N10 wy =>
+ let (w,r) := w7_mul_add_n1 3 wy wx W0 in
+ if w7_eq0 w then N10 r
+ else N11 (WW (extend3 w6 w) r)
+ | N7 wx, N11 wy =>
+ let (w,r) := w7_mul_add_n1 4 wy wx W0 in
+ if w7_eq0 w then N11 r
+ else N12 (WW (extend4 w6 w) r)
+ | N7 wx, N12 wy =>
+ let (w,r) := w7_mul_add_n1 5 wy wx W0 in
+ if w7_eq0 w then N12 r
+ else Nn 0 (WW (extend5 w6 w) r)
+ | N7 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend5 w6 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N8 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 8 wx wy w_0 in
+ if w0_eq0 w then N8 r
+ else N9 (WW (extend7 w0 (WW w_0 w)) r)
+ | N8 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 7 wx wy W0 in
+ if w1_eq0 w then N8 r
+ else N9 (WW (extend7 w0 w) r)
+ | N8 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 6 wx wy W0 in
+ if w2_eq0 w then N8 r
+ else N9 (WW (extend6 w1 w) r)
+ | N8 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 5 wx wy W0 in
+ if w3_eq0 w then N8 r
+ else N9 (WW (extend5 w2 w) r)
+ | N8 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 4 wx wy W0 in
+ if w4_eq0 w then N8 r
+ else N9 (WW (extend4 w3 w) r)
+ | N8 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 3 wx wy W0 in
+ if w5_eq0 w then N8 r
+ else N9 (WW (extend3 w4 w) r)
+ | N8 wx, N6 wy =>
+ let (w,r) := w6_mul_add_n1 2 wx wy W0 in
+ if w6_eq0 w then N8 r
+ else N9 (WW (extend2 w5 w) r)
+ | N8 wx, N7 wy =>
+ let (w,r) := w7_mul_add_n1 1 wx wy W0 in
+ if w7_eq0 w then N8 r
+ else N9 (WW (extend1 w6 w) r)
+ | N8 wx, N8 wy =>
+ N9 (w8_mul_c wx wy)
+ | N8 wx, N9 wy =>
+ let (w,r) := w8_mul_add_n1 1 wy wx W0 in
+ if w8_eq0 w then N9 r
+ else N10 (WW (extend1 w7 w) r)
+ | N8 wx, N10 wy =>
+ let (w,r) := w8_mul_add_n1 2 wy wx W0 in
+ if w8_eq0 w then N10 r
+ else N11 (WW (extend2 w7 w) r)
+ | N8 wx, N11 wy =>
+ let (w,r) := w8_mul_add_n1 3 wy wx W0 in
+ if w8_eq0 w then N11 r
+ else N12 (WW (extend3 w7 w) r)
+ | N8 wx, N12 wy =>
+ let (w,r) := w8_mul_add_n1 4 wy wx W0 in
+ if w8_eq0 w then N12 r
+ else Nn 0 (WW (extend4 w7 w) r)
+ | N8 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend4 w7 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N9 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 9 wx wy w_0 in
+ if w0_eq0 w then N9 r
+ else N10 (WW (extend8 w0 (WW w_0 w)) r)
+ | N9 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 8 wx wy W0 in
+ if w1_eq0 w then N9 r
+ else N10 (WW (extend8 w0 w) r)
+ | N9 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 7 wx wy W0 in
+ if w2_eq0 w then N9 r
+ else N10 (WW (extend7 w1 w) r)
+ | N9 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 6 wx wy W0 in
+ if w3_eq0 w then N9 r
+ else N10 (WW (extend6 w2 w) r)
+ | N9 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 5 wx wy W0 in
+ if w4_eq0 w then N9 r
+ else N10 (WW (extend5 w3 w) r)
+ | N9 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 4 wx wy W0 in
+ if w5_eq0 w then N9 r
+ else N10 (WW (extend4 w4 w) r)
+ | N9 wx, N6 wy =>
+ let (w,r) := w6_mul_add_n1 3 wx wy W0 in
+ if w6_eq0 w then N9 r
+ else N10 (WW (extend3 w5 w) r)
+ | N9 wx, N7 wy =>
+ let (w,r) := w7_mul_add_n1 2 wx wy W0 in
+ if w7_eq0 w then N9 r
+ else N10 (WW (extend2 w6 w) r)
+ | N9 wx, N8 wy =>
+ let (w,r) := w8_mul_add_n1 1 wx wy W0 in
+ if w8_eq0 w then N9 r
+ else N10 (WW (extend1 w7 w) r)
+ | N9 wx, N9 wy =>
+ N10 (w9_mul_c wx wy)
+ | N9 wx, N10 wy =>
+ let (w,r) := w9_mul_add_n1 1 wy wx W0 in
+ if w9_eq0 w then N10 r
+ else N11 (WW (extend1 w8 w) r)
+ | N9 wx, N11 wy =>
+ let (w,r) := w9_mul_add_n1 2 wy wx W0 in
+ if w9_eq0 w then N11 r
+ else N12 (WW (extend2 w8 w) r)
+ | N9 wx, N12 wy =>
+ let (w,r) := w9_mul_add_n1 3 wy wx W0 in
+ if w9_eq0 w then N12 r
+ else Nn 0 (WW (extend3 w8 w) r)
+ | N9 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend3 w8 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N10 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 10 wx wy w_0 in
+ if w0_eq0 w then N10 r
+ else N11 (WW (extend9 w0 (WW w_0 w)) r)
+ | N10 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 9 wx wy W0 in
+ if w1_eq0 w then N10 r
+ else N11 (WW (extend9 w0 w) r)
+ | N10 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 8 wx wy W0 in
+ if w2_eq0 w then N10 r
+ else N11 (WW (extend8 w1 w) r)
+ | N10 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 7 wx wy W0 in
+ if w3_eq0 w then N10 r
+ else N11 (WW (extend7 w2 w) r)
+ | N10 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 6 wx wy W0 in
+ if w4_eq0 w then N10 r
+ else N11 (WW (extend6 w3 w) r)
+ | N10 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 5 wx wy W0 in
+ if w5_eq0 w then N10 r
+ else N11 (WW (extend5 w4 w) r)
+ | N10 wx, N6 wy =>
+ let (w,r) := w6_mul_add_n1 4 wx wy W0 in
+ if w6_eq0 w then N10 r
+ else N11 (WW (extend4 w5 w) r)
+ | N10 wx, N7 wy =>
+ let (w,r) := w7_mul_add_n1 3 wx wy W0 in
+ if w7_eq0 w then N10 r
+ else N11 (WW (extend3 w6 w) r)
+ | N10 wx, N8 wy =>
+ let (w,r) := w8_mul_add_n1 2 wx wy W0 in
+ if w8_eq0 w then N10 r
+ else N11 (WW (extend2 w7 w) r)
+ | N10 wx, N9 wy =>
+ let (w,r) := w9_mul_add_n1 1 wx wy W0 in
+ if w9_eq0 w then N10 r
+ else N11 (WW (extend1 w8 w) r)
+ | N10 wx, N10 wy =>
+ N11 (w10_mul_c wx wy)
+ | N10 wx, N11 wy =>
+ let (w,r) := w10_mul_add_n1 1 wy wx W0 in
+ if w10_eq0 w then N11 r
+ else N12 (WW (extend1 w9 w) r)
+ | N10 wx, N12 wy =>
+ let (w,r) := w10_mul_add_n1 2 wy wx W0 in
+ if w10_eq0 w then N12 r
+ else Nn 0 (WW (extend2 w9 w) r)
+ | N10 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend2 w9 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N11 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 11 wx wy w_0 in
+ if w0_eq0 w then N11 r
+ else N12 (WW (extend10 w0 (WW w_0 w)) r)
+ | N11 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 10 wx wy W0 in
+ if w1_eq0 w then N11 r
+ else N12 (WW (extend10 w0 w) r)
+ | N11 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 9 wx wy W0 in
+ if w2_eq0 w then N11 r
+ else N12 (WW (extend9 w1 w) r)
+ | N11 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 8 wx wy W0 in
+ if w3_eq0 w then N11 r
+ else N12 (WW (extend8 w2 w) r)
+ | N11 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 7 wx wy W0 in
+ if w4_eq0 w then N11 r
+ else N12 (WW (extend7 w3 w) r)
+ | N11 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 6 wx wy W0 in
+ if w5_eq0 w then N11 r
+ else N12 (WW (extend6 w4 w) r)
+ | N11 wx, N6 wy =>
+ let (w,r) := w6_mul_add_n1 5 wx wy W0 in
+ if w6_eq0 w then N11 r
+ else N12 (WW (extend5 w5 w) r)
+ | N11 wx, N7 wy =>
+ let (w,r) := w7_mul_add_n1 4 wx wy W0 in
+ if w7_eq0 w then N11 r
+ else N12 (WW (extend4 w6 w) r)
+ | N11 wx, N8 wy =>
+ let (w,r) := w8_mul_add_n1 3 wx wy W0 in
+ if w8_eq0 w then N11 r
+ else N12 (WW (extend3 w7 w) r)
+ | N11 wx, N9 wy =>
+ let (w,r) := w9_mul_add_n1 2 wx wy W0 in
+ if w9_eq0 w then N11 r
+ else N12 (WW (extend2 w8 w) r)
+ | N11 wx, N10 wy =>
+ let (w,r) := w10_mul_add_n1 1 wx wy W0 in
+ if w10_eq0 w then N11 r
+ else N12 (WW (extend1 w9 w) r)
+ | N11 wx, N11 wy =>
+ N12 (w11_mul_c wx wy)
+ | N11 wx, N12 wy =>
+ let (w,r) := w11_mul_add_n1 1 wy wx W0 in
+ if w11_eq0 w then N12 r
+ else Nn 0 (WW (extend1 w10 w) r)
+ | N11 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy (extend1 w10 wx) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | N12 wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) := w0_mul_add_n1 12 wx wy w_0 in
+ if w0_eq0 w then N12 r
+ else Nn 0 (WW (extend11 w0 (WW w_0 w)) r)
+ | N12 wx, N1 wy =>
+ let (w,r) := w1_mul_add_n1 11 wx wy W0 in
+ if w1_eq0 w then N12 r
+ else Nn 0 (WW (extend11 w0 w) r)
+ | N12 wx, N2 wy =>
+ let (w,r) := w2_mul_add_n1 10 wx wy W0 in
+ if w2_eq0 w then N12 r
+ else Nn 0 (WW (extend10 w1 w) r)
+ | N12 wx, N3 wy =>
+ let (w,r) := w3_mul_add_n1 9 wx wy W0 in
+ if w3_eq0 w then N12 r
+ else Nn 0 (WW (extend9 w2 w) r)
+ | N12 wx, N4 wy =>
+ let (w,r) := w4_mul_add_n1 8 wx wy W0 in
+ if w4_eq0 w then N12 r
+ else Nn 0 (WW (extend8 w3 w) r)
+ | N12 wx, N5 wy =>
+ let (w,r) := w5_mul_add_n1 7 wx wy W0 in
+ if w5_eq0 w then N12 r
+ else Nn 0 (WW (extend7 w4 w) r)
+ | N12 wx, N6 wy =>
+ let (w,r) := w6_mul_add_n1 6 wx wy W0 in
+ if w6_eq0 w then N12 r
+ else Nn 0 (WW (extend6 w5 w) r)
+ | N12 wx, N7 wy =>
+ let (w,r) := w7_mul_add_n1 5 wx wy W0 in
+ if w7_eq0 w then N12 r
+ else Nn 0 (WW (extend5 w6 w) r)
+ | N12 wx, N8 wy =>
+ let (w,r) := w8_mul_add_n1 4 wx wy W0 in
+ if w8_eq0 w then N12 r
+ else Nn 0 (WW (extend4 w7 w) r)
+ | N12 wx, N9 wy =>
+ let (w,r) := w9_mul_add_n1 3 wx wy W0 in
+ if w9_eq0 w then N12 r
+ else Nn 0 (WW (extend3 w8 w) r)
+ | N12 wx, N10 wy =>
+ let (w,r) := w10_mul_add_n1 2 wx wy W0 in
+ if w10_eq0 w then N12 r
+ else Nn 0 (WW (extend2 w9 w) r)
+ | N12 wx, N11 wy =>
+ let (w,r) := w11_mul_add_n1 1 wx wy W0 in
+ if w11_eq0 w then N12 r
+ else Nn 0 (WW (extend1 w10 w) r)
+ | N12 wx, N12 wy =>
+ Nn 0 (w12_mul_c wx wy)
+ | N12 wx, Nn n wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wy wx W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N0 wy =>
+ if w0_eq0 wy then zero
+ else
+ let (w,r) :=
+ gen_mul_add_mn1 w_0 (fun r => extend11 w0 (WW w_0 r))
+ w12_op.(znz_0W) w12_op.(znz_WW)
+ (w0_mul_add_n1 12) (S n) wx wy w_0 in
+ if w0_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (extend12 w0 (WW w_0 w))) r)
+ | Nn n wx, N1 wy =>
+ let (w,r) :=
+ gen_mul_add_mn1 W0 (fun r => extend11 w0 r)
+ w12_op.(znz_0W) w12_op.(znz_WW)
+ (w1_mul_add_n1 11) (S n) wx wy W0 in
+ if w1_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (extend12 w0 w)) r)
+ | Nn n wx, N2 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend10 w1 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N3 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend9 w2 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N4 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend8 w3 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N5 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend7 w4 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N6 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend6 w5 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N7 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend5 w6 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N8 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend4 w7 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N9 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend3 w8 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N10 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend2 w9 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N11 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx (extend1 w10 wy) W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, N12 wy =>
+ let (w,r) := w12_mul_add_n1 (S n) wx wy W0 in
+ if w12_eq0 w then Nn n r
+ else Nn (S n) (WW (extend n w12 (WW W0 w)) r)
+ | Nn n wx, Nn m wy =>
+ match extend_to_max w12 n m wx wy with
+ | inl wx' =>
+ let op := make_op m in
+ reduce_n (S m) (op.(znz_mul_c) wx' wy)
+ | inr wy' =>
+ let op := make_op n in
+ reduce_n (S n) (op.(znz_mul_c) wx wy')
+ end
+ end.
+
+ Definition w0_square_c := w0_op.(znz_square_c).
+ Definition w1_square_c := w1_op.(znz_square_c).
+ Definition w2_square_c := w2_op.(znz_square_c).
+ Definition w3_square_c := w3_op.(znz_square_c).
+ Definition w4_square_c := w4_op.(znz_square_c).
+ Definition w5_square_c := w5_op.(znz_square_c).
+ Definition w6_square_c := w6_op.(znz_square_c).
+ Definition w7_square_c := w7_op.(znz_square_c).
+ Definition w8_square_c := w8_op.(znz_square_c).
+ Definition w9_square_c := w9_op.(znz_square_c).
+ Definition w10_square_c := w10_op.(znz_square_c).
+ Definition w11_square_c := w11_op.(znz_square_c).
+ Definition w12_square_c := w12_op.(znz_square_c).
+
+ Definition square x :=
+ match x with
+ | N0 wx => reduce_1 (w0_square_c wx)
+ | N1 wx => N2 (w1_square_c wx)
+ | N2 wx => N3 (w2_square_c wx)
+ | N3 wx => N4 (w3_square_c wx)
+ | N4 wx => N5 (w4_square_c wx)
+ | N5 wx => N6 (w5_square_c wx)
+ | N6 wx => N7 (w6_square_c wx)
+ | N7 wx => N8 (w7_square_c wx)
+ | N8 wx => N9 (w8_square_c wx)
+ | N9 wx => N10 (w9_square_c wx)
+ | N10 wx => N11 (w10_square_c wx)
+ | N11 wx => N12 (w11_square_c wx)
+ | N12 wx => Nn 0 (w12_square_c wx)
+ | Nn n wx =>
+ let op := make_op n in
+ Nn (S n) (op.(znz_square_c) wx)
+ end.
+
+ Fixpoint power_pos (x:t) (p:positive) {struct p} : t :=
+ match p with
+ | xH => x
+ | xO p => square (power_pos x p)
+ | xI p => mul (square (power_pos x p)) x
+ end.
+
+ Definition w0_sqrt := w0_op.(znz_sqrt).
+ Definition w1_sqrt := w1_op.(znz_sqrt).
+ Definition w2_sqrt := w2_op.(znz_sqrt).
+ Definition w3_sqrt := w3_op.(znz_sqrt).
+ Definition w4_sqrt := w4_op.(znz_sqrt).
+ Definition w5_sqrt := w5_op.(znz_sqrt).
+ Definition w6_sqrt := w6_op.(znz_sqrt).
+ Definition w7_sqrt := w7_op.(znz_sqrt).
+ Definition w8_sqrt := w8_op.(znz_sqrt).
+ Definition w9_sqrt := w9_op.(znz_sqrt).
+ Definition w10_sqrt := w10_op.(znz_sqrt).
+ Definition w11_sqrt := w11_op.(znz_sqrt).
+ Definition w12_sqrt := w12_op.(znz_sqrt).
+
+ Definition sqrt x :=
+ match x with
+ | N0 wx => reduce_0 (w0_sqrt wx)
+ | N1 wx => reduce_1 (w1_sqrt wx)
+ | N2 wx => reduce_2 (w2_sqrt wx)
+ | N3 wx => reduce_3 (w3_sqrt wx)
+ | N4 wx => reduce_4 (w4_sqrt wx)
+ | N5 wx => reduce_5 (w5_sqrt wx)
+ | N6 wx => reduce_6 (w6_sqrt wx)
+ | N7 wx => reduce_7 (w7_sqrt wx)
+ | N8 wx => reduce_8 (w8_sqrt wx)
+ | N9 wx => reduce_9 (w9_sqrt wx)
+ | N10 wx => reduce_10 (w10_sqrt wx)
+ | N11 wx => reduce_11 (w11_sqrt wx)
+ | N12 wx => reduce_12 (w12_sqrt wx)
+ | Nn n wx =>
+ let op := make_op n in
+ reduce_n n (op.(znz_sqrt) wx)
+ end.
+
+ Definition w0_div_gt := w0_op.(znz_div_gt).
+ Definition w1_div_gt := w1_op.(znz_div_gt).
+ Definition w2_div_gt := w2_op.(znz_div_gt).
+ Definition w3_div_gt := w3_op.(znz_div_gt).
+ Definition w4_div_gt := w4_op.(znz_div_gt).
+ Definition w5_div_gt := w5_op.(znz_div_gt).
+ Definition w6_div_gt := w6_op.(znz_div_gt).
+ Definition w7_div_gt := w7_op.(znz_div_gt).
+ Definition w8_div_gt := w8_op.(znz_div_gt).
+ Definition w9_div_gt := w9_op.(znz_div_gt).
+ Definition w10_div_gt := w10_op.(znz_div_gt).
+ Definition w11_div_gt := w11_op.(znz_div_gt).
+ Definition w12_div_gt := w12_op.(znz_div_gt).
+
+ Definition w0_divn1 :=
+ gen_divn1 w0_op.(znz_digits) w0_op.(znz_0)
+ w0_op.(znz_WW) w0_op.(znz_head0)
+ w0_op.(znz_add_mul_div) w0_op.(znz_div21).
+ Definition w1_divn1 :=
+ gen_divn1 w1_op.(znz_digits) w1_op.(znz_0)
+ w1_op.(znz_WW) w1_op.(znz_head0)
+ w1_op.(znz_add_mul_div) w1_op.(znz_div21).
+ Definition w2_divn1 :=
+ gen_divn1 w2_op.(znz_digits) w2_op.(znz_0)
+ w2_op.(znz_WW) w2_op.(znz_head0)
+ w2_op.(znz_add_mul_div) w2_op.(znz_div21).
+ Definition w3_divn1 :=
+ gen_divn1 w3_op.(znz_digits) w3_op.(znz_0)
+ w3_op.(znz_WW) w3_op.(znz_head0)
+ w3_op.(znz_add_mul_div) w3_op.(znz_div21).
+ Definition w4_divn1 :=
+ gen_divn1 w4_op.(znz_digits) w4_op.(znz_0)
+ w4_op.(znz_WW) w4_op.(znz_head0)
+ w4_op.(znz_add_mul_div) w4_op.(znz_div21).
+ Definition w5_divn1 :=
+ gen_divn1 w5_op.(znz_digits) w5_op.(znz_0)
+ w5_op.(znz_WW) w5_op.(znz_head0)
+ w5_op.(znz_add_mul_div) w5_op.(znz_div21).
+ Definition w6_divn1 :=
+ gen_divn1 w6_op.(znz_digits) w6_op.(znz_0)
+ w6_op.(znz_WW) w6_op.(znz_head0)
+ w6_op.(znz_add_mul_div) w6_op.(znz_div21).
+ Definition w7_divn1 :=
+ gen_divn1 w7_op.(znz_digits) w7_op.(znz_0)
+ w7_op.(znz_WW) w7_op.(znz_head0)
+ w7_op.(znz_add_mul_div) w7_op.(znz_div21).
+ Definition w8_divn1 :=
+ gen_divn1 w8_op.(znz_digits) w8_op.(znz_0)
+ w8_op.(znz_WW) w8_op.(znz_head0)
+ w8_op.(znz_add_mul_div) w8_op.(znz_div21).
+ Definition w9_divn1 :=
+ gen_divn1 w9_op.(znz_digits) w9_op.(znz_0)
+ w9_op.(znz_WW) w9_op.(znz_head0)
+ w9_op.(znz_add_mul_div) w9_op.(znz_div21).
+ Definition w10_divn1 :=
+ gen_divn1 w10_op.(znz_digits) w10_op.(znz_0)
+ w10_op.(znz_WW) w10_op.(znz_head0)
+ w10_op.(znz_add_mul_div) w10_op.(znz_div21).
+ Definition w11_divn1 :=
+ gen_divn1 w11_op.(znz_digits) w11_op.(znz_0)
+ w11_op.(znz_WW) w11_op.(znz_head0)
+ w11_op.(znz_add_mul_div) w11_op.(znz_div21).
+ Definition w12_divn1 :=
+ gen_divn1 w12_op.(znz_digits) w12_op.(znz_0)
+ w12_op.(znz_WW) w12_op.(znz_head0)
+ w12_op.(znz_add_mul_div) w12_op.(znz_div21).
+
+ Definition div_gt x y :=
+ match x, y with
+ | N0 wx, N0 wy => let (q, r):= w0_div_gt wx wy in (reduce_0 q, reduce_0 r)
+ | N0 wx, N1 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 0 wx in
+ let (q, r):= w1_div_gt wx' wy in
+ (reduce_1 q, reduce_1 r)
+ | N0 wx, N2 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 1 wx in
+ let (q, r):= w2_div_gt wx' wy in
+ (reduce_2 q, reduce_2 r)
+ | N0 wx, N3 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 2 wx in
+ let (q, r):= w3_div_gt wx' wy in
+ (reduce_3 q, reduce_3 r)
+ | N0 wx, N4 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 3 wx in
+ let (q, r):= w4_div_gt wx' wy in
+ (reduce_4 q, reduce_4 r)
+ | N0 wx, N5 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 4 wx in
+ let (q, r):= w5_div_gt wx' wy in
+ (reduce_5 q, reduce_5 r)
+ | N0 wx, N6 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 5 wx in
+ let (q, r):= w6_div_gt wx' wy in
+ (reduce_6 q, reduce_6 r)
+ | N0 wx, N7 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 6 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N0 wx, N8 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 7 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N0 wx, N9 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 8 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N0 wx, N10 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 9 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N0 wx, N11 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 10 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N0 wx, N12 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 11 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N0 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w0_op.(znz_0W) 12 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N1 wx, N0 wy => let (q, r):= w0_divn1 1 wx wy in (reduce_1 q, reduce_0 r)
+ | N1 wx, N1 wy => let (q, r):= w1_div_gt wx wy in (reduce_1 q, reduce_1 r)
+ | N1 wx, N2 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 0 wx in
+ let (q, r):= w2_div_gt wx' wy in
+ (reduce_2 q, reduce_2 r)
+ | N1 wx, N3 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 1 wx in
+ let (q, r):= w3_div_gt wx' wy in
+ (reduce_3 q, reduce_3 r)
+ | N1 wx, N4 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 2 wx in
+ let (q, r):= w4_div_gt wx' wy in
+ (reduce_4 q, reduce_4 r)
+ | N1 wx, N5 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 3 wx in
+ let (q, r):= w5_div_gt wx' wy in
+ (reduce_5 q, reduce_5 r)
+ | N1 wx, N6 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 4 wx in
+ let (q, r):= w6_div_gt wx' wy in
+ (reduce_6 q, reduce_6 r)
+ | N1 wx, N7 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 5 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N1 wx, N8 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 6 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N1 wx, N9 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 7 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N1 wx, N10 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 8 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N1 wx, N11 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 9 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N1 wx, N12 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 10 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N1 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w1_op.(znz_0W) 11 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N2 wx, N0 wy => let (q, r):= w0_divn1 2 wx wy in (reduce_2 q, reduce_0 r)
+ | N2 wx, N1 wy => let (q, r):= w1_divn1 1 wx wy in (reduce_2 q, reduce_1 r)
+ | N2 wx, N2 wy => let (q, r):= w2_div_gt wx wy in (reduce_2 q, reduce_2 r)
+ | N2 wx, N3 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 0 wx in
+ let (q, r):= w3_div_gt wx' wy in
+ (reduce_3 q, reduce_3 r)
+ | N2 wx, N4 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 1 wx in
+ let (q, r):= w4_div_gt wx' wy in
+ (reduce_4 q, reduce_4 r)
+ | N2 wx, N5 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 2 wx in
+ let (q, r):= w5_div_gt wx' wy in
+ (reduce_5 q, reduce_5 r)
+ | N2 wx, N6 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 3 wx in
+ let (q, r):= w6_div_gt wx' wy in
+ (reduce_6 q, reduce_6 r)
+ | N2 wx, N7 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 4 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N2 wx, N8 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 5 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N2 wx, N9 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 6 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N2 wx, N10 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 7 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N2 wx, N11 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 8 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N2 wx, N12 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 9 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N2 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w2_op.(znz_0W) 10 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N3 wx, N0 wy => let (q, r):= w0_divn1 3 wx wy in (reduce_3 q, reduce_0 r)
+ | N3 wx, N1 wy => let (q, r):= w1_divn1 2 wx wy in (reduce_3 q, reduce_1 r)
+ | N3 wx, N2 wy => let (q, r):= w2_divn1 1 wx wy in (reduce_3 q, reduce_2 r)
+ | N3 wx, N3 wy => let (q, r):= w3_div_gt wx wy in (reduce_3 q, reduce_3 r)
+ | N3 wx, N4 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 0 wx in
+ let (q, r):= w4_div_gt wx' wy in
+ (reduce_4 q, reduce_4 r)
+ | N3 wx, N5 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 1 wx in
+ let (q, r):= w5_div_gt wx' wy in
+ (reduce_5 q, reduce_5 r)
+ | N3 wx, N6 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 2 wx in
+ let (q, r):= w6_div_gt wx' wy in
+ (reduce_6 q, reduce_6 r)
+ | N3 wx, N7 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 3 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N3 wx, N8 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 4 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N3 wx, N9 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 5 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N3 wx, N10 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 6 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N3 wx, N11 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 7 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N3 wx, N12 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 8 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N3 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w3_op.(znz_0W) 9 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N4 wx, N0 wy => let (q, r):= w0_divn1 4 wx wy in (reduce_4 q, reduce_0 r)
+ | N4 wx, N1 wy => let (q, r):= w1_divn1 3 wx wy in (reduce_4 q, reduce_1 r)
+ | N4 wx, N2 wy => let (q, r):= w2_divn1 2 wx wy in (reduce_4 q, reduce_2 r)
+ | N4 wx, N3 wy => let (q, r):= w3_divn1 1 wx wy in (reduce_4 q, reduce_3 r)
+ | N4 wx, N4 wy => let (q, r):= w4_div_gt wx wy in (reduce_4 q, reduce_4 r)
+ | N4 wx, N5 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 0 wx in
+ let (q, r):= w5_div_gt wx' wy in
+ (reduce_5 q, reduce_5 r)
+ | N4 wx, N6 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 1 wx in
+ let (q, r):= w6_div_gt wx' wy in
+ (reduce_6 q, reduce_6 r)
+ | N4 wx, N7 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 2 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N4 wx, N8 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 3 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N4 wx, N9 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 4 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N4 wx, N10 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 5 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N4 wx, N11 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 6 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N4 wx, N12 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 7 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N4 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w4_op.(znz_0W) 8 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N5 wx, N0 wy => let (q, r):= w0_divn1 5 wx wy in (reduce_5 q, reduce_0 r)
+ | N5 wx, N1 wy => let (q, r):= w1_divn1 4 wx wy in (reduce_5 q, reduce_1 r)
+ | N5 wx, N2 wy => let (q, r):= w2_divn1 3 wx wy in (reduce_5 q, reduce_2 r)
+ | N5 wx, N3 wy => let (q, r):= w3_divn1 2 wx wy in (reduce_5 q, reduce_3 r)
+ | N5 wx, N4 wy => let (q, r):= w4_divn1 1 wx wy in (reduce_5 q, reduce_4 r)
+ | N5 wx, N5 wy => let (q, r):= w5_div_gt wx wy in (reduce_5 q, reduce_5 r)
+ | N5 wx, N6 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 0 wx in
+ let (q, r):= w6_div_gt wx' wy in
+ (reduce_6 q, reduce_6 r)
+ | N5 wx, N7 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 1 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N5 wx, N8 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 2 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N5 wx, N9 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 3 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N5 wx, N10 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 4 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N5 wx, N11 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 5 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N5 wx, N12 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 6 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N5 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w5_op.(znz_0W) 7 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N6 wx, N0 wy => let (q, r):= w0_divn1 6 wx wy in (reduce_6 q, reduce_0 r)
+ | N6 wx, N1 wy => let (q, r):= w1_divn1 5 wx wy in (reduce_6 q, reduce_1 r)
+ | N6 wx, N2 wy => let (q, r):= w2_divn1 4 wx wy in (reduce_6 q, reduce_2 r)
+ | N6 wx, N3 wy => let (q, r):= w3_divn1 3 wx wy in (reduce_6 q, reduce_3 r)
+ | N6 wx, N4 wy => let (q, r):= w4_divn1 2 wx wy in (reduce_6 q, reduce_4 r)
+ | N6 wx, N5 wy => let (q, r):= w5_divn1 1 wx wy in (reduce_6 q, reduce_5 r)
+ | N6 wx, N6 wy => let (q, r):= w6_div_gt wx wy in (reduce_6 q, reduce_6 r)
+ | N6 wx, N7 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 0 wx in
+ let (q, r):= w7_div_gt wx' wy in
+ (reduce_7 q, reduce_7 r)
+ | N6 wx, N8 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 1 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N6 wx, N9 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 2 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N6 wx, N10 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 3 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N6 wx, N11 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 4 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N6 wx, N12 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 5 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N6 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w6_op.(znz_0W) 6 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N7 wx, N0 wy => let (q, r):= w0_divn1 7 wx wy in (reduce_7 q, reduce_0 r)
+ | N7 wx, N1 wy => let (q, r):= w1_divn1 6 wx wy in (reduce_7 q, reduce_1 r)
+ | N7 wx, N2 wy => let (q, r):= w2_divn1 5 wx wy in (reduce_7 q, reduce_2 r)
+ | N7 wx, N3 wy => let (q, r):= w3_divn1 4 wx wy in (reduce_7 q, reduce_3 r)
+ | N7 wx, N4 wy => let (q, r):= w4_divn1 3 wx wy in (reduce_7 q, reduce_4 r)
+ | N7 wx, N5 wy => let (q, r):= w5_divn1 2 wx wy in (reduce_7 q, reduce_5 r)
+ | N7 wx, N6 wy => let (q, r):= w6_divn1 1 wx wy in (reduce_7 q, reduce_6 r)
+ | N7 wx, N7 wy => let (q, r):= w7_div_gt wx wy in (reduce_7 q, reduce_7 r)
+ | N7 wx, N8 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 0 wx in
+ let (q, r):= w8_div_gt wx' wy in
+ (reduce_8 q, reduce_8 r)
+ | N7 wx, N9 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 1 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N7 wx, N10 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 2 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N7 wx, N11 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 3 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N7 wx, N12 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 4 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N7 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w7_op.(znz_0W) 5 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N8 wx, N0 wy => let (q, r):= w0_divn1 8 wx wy in (reduce_8 q, reduce_0 r)
+ | N8 wx, N1 wy => let (q, r):= w1_divn1 7 wx wy in (reduce_8 q, reduce_1 r)
+ | N8 wx, N2 wy => let (q, r):= w2_divn1 6 wx wy in (reduce_8 q, reduce_2 r)
+ | N8 wx, N3 wy => let (q, r):= w3_divn1 5 wx wy in (reduce_8 q, reduce_3 r)
+ | N8 wx, N4 wy => let (q, r):= w4_divn1 4 wx wy in (reduce_8 q, reduce_4 r)
+ | N8 wx, N5 wy => let (q, r):= w5_divn1 3 wx wy in (reduce_8 q, reduce_5 r)
+ | N8 wx, N6 wy => let (q, r):= w6_divn1 2 wx wy in (reduce_8 q, reduce_6 r)
+ | N8 wx, N7 wy => let (q, r):= w7_divn1 1 wx wy in (reduce_8 q, reduce_7 r)
+ | N8 wx, N8 wy => let (q, r):= w8_div_gt wx wy in (reduce_8 q, reduce_8 r)
+ | N8 wx, N9 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 0 wx in
+ let (q, r):= w9_div_gt wx' wy in
+ (reduce_9 q, reduce_9 r)
+ | N8 wx, N10 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 1 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N8 wx, N11 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 2 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N8 wx, N12 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 3 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N8 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w8_op.(znz_0W) 4 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N9 wx, N0 wy => let (q, r):= w0_divn1 9 wx wy in (reduce_9 q, reduce_0 r)
+ | N9 wx, N1 wy => let (q, r):= w1_divn1 8 wx wy in (reduce_9 q, reduce_1 r)
+ | N9 wx, N2 wy => let (q, r):= w2_divn1 7 wx wy in (reduce_9 q, reduce_2 r)
+ | N9 wx, N3 wy => let (q, r):= w3_divn1 6 wx wy in (reduce_9 q, reduce_3 r)
+ | N9 wx, N4 wy => let (q, r):= w4_divn1 5 wx wy in (reduce_9 q, reduce_4 r)
+ | N9 wx, N5 wy => let (q, r):= w5_divn1 4 wx wy in (reduce_9 q, reduce_5 r)
+ | N9 wx, N6 wy => let (q, r):= w6_divn1 3 wx wy in (reduce_9 q, reduce_6 r)
+ | N9 wx, N7 wy => let (q, r):= w7_divn1 2 wx wy in (reduce_9 q, reduce_7 r)
+ | N9 wx, N8 wy => let (q, r):= w8_divn1 1 wx wy in (reduce_9 q, reduce_8 r)
+ | N9 wx, N9 wy => let (q, r):= w9_div_gt wx wy in (reduce_9 q, reduce_9 r)
+ | N9 wx, N10 wy =>
+ let wx':= GenBase.extend w9_op.(znz_0W) 0 wx in
+ let (q, r):= w10_div_gt wx' wy in
+ (reduce_10 q, reduce_10 r)
+ | N9 wx, N11 wy =>
+ let wx':= GenBase.extend w9_op.(znz_0W) 1 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N9 wx, N12 wy =>
+ let wx':= GenBase.extend w9_op.(znz_0W) 2 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N9 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w9_op.(znz_0W) 3 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N10 wx, N0 wy => let (q, r):= w0_divn1 10 wx wy in (reduce_10 q, reduce_0 r)
+ | N10 wx, N1 wy => let (q, r):= w1_divn1 9 wx wy in (reduce_10 q, reduce_1 r)
+ | N10 wx, N2 wy => let (q, r):= w2_divn1 8 wx wy in (reduce_10 q, reduce_2 r)
+ | N10 wx, N3 wy => let (q, r):= w3_divn1 7 wx wy in (reduce_10 q, reduce_3 r)
+ | N10 wx, N4 wy => let (q, r):= w4_divn1 6 wx wy in (reduce_10 q, reduce_4 r)
+ | N10 wx, N5 wy => let (q, r):= w5_divn1 5 wx wy in (reduce_10 q, reduce_5 r)
+ | N10 wx, N6 wy => let (q, r):= w6_divn1 4 wx wy in (reduce_10 q, reduce_6 r)
+ | N10 wx, N7 wy => let (q, r):= w7_divn1 3 wx wy in (reduce_10 q, reduce_7 r)
+ | N10 wx, N8 wy => let (q, r):= w8_divn1 2 wx wy in (reduce_10 q, reduce_8 r)
+ | N10 wx, N9 wy => let (q, r):= w9_divn1 1 wx wy in (reduce_10 q, reduce_9 r)
+ | N10 wx, N10 wy => let (q, r):= w10_div_gt wx wy in (reduce_10 q, reduce_10 r)
+ | N10 wx, N11 wy =>
+ let wx':= GenBase.extend w10_op.(znz_0W) 0 wx in
+ let (q, r):= w11_div_gt wx' wy in
+ (reduce_11 q, reduce_11 r)
+ | N10 wx, N12 wy =>
+ let wx':= GenBase.extend w10_op.(znz_0W) 1 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N10 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w10_op.(znz_0W) 2 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N11 wx, N0 wy => let (q, r):= w0_divn1 11 wx wy in (reduce_11 q, reduce_0 r)
+ | N11 wx, N1 wy => let (q, r):= w1_divn1 10 wx wy in (reduce_11 q, reduce_1 r)
+ | N11 wx, N2 wy => let (q, r):= w2_divn1 9 wx wy in (reduce_11 q, reduce_2 r)
+ | N11 wx, N3 wy => let (q, r):= w3_divn1 8 wx wy in (reduce_11 q, reduce_3 r)
+ | N11 wx, N4 wy => let (q, r):= w4_divn1 7 wx wy in (reduce_11 q, reduce_4 r)
+ | N11 wx, N5 wy => let (q, r):= w5_divn1 6 wx wy in (reduce_11 q, reduce_5 r)
+ | N11 wx, N6 wy => let (q, r):= w6_divn1 5 wx wy in (reduce_11 q, reduce_6 r)
+ | N11 wx, N7 wy => let (q, r):= w7_divn1 4 wx wy in (reduce_11 q, reduce_7 r)
+ | N11 wx, N8 wy => let (q, r):= w8_divn1 3 wx wy in (reduce_11 q, reduce_8 r)
+ | N11 wx, N9 wy => let (q, r):= w9_divn1 2 wx wy in (reduce_11 q, reduce_9 r)
+ | N11 wx, N10 wy => let (q, r):= w10_divn1 1 wx wy in (reduce_11 q, reduce_10 r)
+ | N11 wx, N11 wy => let (q, r):= w11_div_gt wx wy in (reduce_11 q, reduce_11 r)
+ | N11 wx, N12 wy =>
+ let wx':= GenBase.extend w11_op.(znz_0W) 0 wx in
+ let (q, r):= w12_div_gt wx' wy in
+ (reduce_12 q, reduce_12 r)
+ | N11 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w11_op.(znz_0W) 1 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | N12 wx, N0 wy => let (q, r):= w0_divn1 12 wx wy in (reduce_12 q, reduce_0 r)
+ | N12 wx, N1 wy => let (q, r):= w1_divn1 11 wx wy in (reduce_12 q, reduce_1 r)
+ | N12 wx, N2 wy => let (q, r):= w2_divn1 10 wx wy in (reduce_12 q, reduce_2 r)
+ | N12 wx, N3 wy => let (q, r):= w3_divn1 9 wx wy in (reduce_12 q, reduce_3 r)
+ | N12 wx, N4 wy => let (q, r):= w4_divn1 8 wx wy in (reduce_12 q, reduce_4 r)
+ | N12 wx, N5 wy => let (q, r):= w5_divn1 7 wx wy in (reduce_12 q, reduce_5 r)
+ | N12 wx, N6 wy => let (q, r):= w6_divn1 6 wx wy in (reduce_12 q, reduce_6 r)
+ | N12 wx, N7 wy => let (q, r):= w7_divn1 5 wx wy in (reduce_12 q, reduce_7 r)
+ | N12 wx, N8 wy => let (q, r):= w8_divn1 4 wx wy in (reduce_12 q, reduce_8 r)
+ | N12 wx, N9 wy => let (q, r):= w9_divn1 3 wx wy in (reduce_12 q, reduce_9 r)
+ | N12 wx, N10 wy => let (q, r):= w10_divn1 2 wx wy in (reduce_12 q, reduce_10 r)
+ | N12 wx, N11 wy => let (q, r):= w11_divn1 1 wx wy in (reduce_12 q, reduce_11 r)
+ | N12 wx, N12 wy => let (q, r):= w12_div_gt wx wy in (reduce_12 q, reduce_12 r)
+ | N12 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w12_op.(znz_0W) 0 wx) in
+ let (q, r):= (make_op n).(znz_div_gt) wx' wy in
+ (reduce_n n q, reduce_n n r)
+ | Nn n wx, N0 wy =>
+ let wy':= GenBase.extend w0_op.(znz_0W) 11 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N1 wy =>
+ let wy':= GenBase.extend w1_op.(znz_0W) 10 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N2 wy =>
+ let wy':= GenBase.extend w2_op.(znz_0W) 9 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N3 wy =>
+ let wy':= GenBase.extend w3_op.(znz_0W) 8 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N4 wy =>
+ let wy':= GenBase.extend w4_op.(znz_0W) 7 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N5 wy =>
+ let wy':= GenBase.extend w5_op.(znz_0W) 6 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N6 wy =>
+ let wy':= GenBase.extend w6_op.(znz_0W) 5 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N7 wy =>
+ let wy':= GenBase.extend w7_op.(znz_0W) 4 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N8 wy =>
+ let wy':= GenBase.extend w8_op.(znz_0W) 3 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N9 wy =>
+ let wy':= GenBase.extend w9_op.(znz_0W) 2 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N10 wy =>
+ let wy':= GenBase.extend w10_op.(znz_0W) 1 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N11 wy =>
+ let wy':= GenBase.extend w11_op.(znz_0W) 0 wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, N12 wy =>
+ let wy':= wy in
+ let (q, r):= w12_divn1 (S n) wx wy' in
+ (reduce_n n q, reduce_12 r)
+ | Nn n wx, Nn m wy =>
+ match extend_to_max w12 n m wx wy with
+ | inl wx' =>
+ let (q, r):= (make_op m).(znz_div) wx' wy in
+ (reduce_n m q, reduce_n m r)
+ | inr wy' =>
+ let (q, r):= (make_op n).(znz_div) wx wy' in
+ (reduce_n n q, reduce_n n r)
+ end
+ end.
+
+ Definition div_eucl x y :=
+ match compare x y with
+ | Eq => (one, zero)
+ | Lt => (zero, x)
+ | Gt => div_gt x y
+ end.
+
+ Definition div x y := fst (div_eucl x y).
+
+ Definition w0_mod_gt := w0_op.(znz_mod_gt).
+ Definition w1_mod_gt := w1_op.(znz_mod_gt).
+ Definition w2_mod_gt := w2_op.(znz_mod_gt).
+ Definition w3_mod_gt := w3_op.(znz_mod_gt).
+ Definition w4_mod_gt := w4_op.(znz_mod_gt).
+ Definition w5_mod_gt := w5_op.(znz_mod_gt).
+ Definition w6_mod_gt := w6_op.(znz_mod_gt).
+ Definition w7_mod_gt := w7_op.(znz_mod_gt).
+ Definition w8_mod_gt := w8_op.(znz_mod_gt).
+ Definition w9_mod_gt := w9_op.(znz_mod_gt).
+ Definition w10_mod_gt := w10_op.(znz_mod_gt).
+ Definition w11_mod_gt := w11_op.(znz_mod_gt).
+ Definition w12_mod_gt := w12_op.(znz_mod_gt).
+
+ Definition w0_modn1 :=
+ gen_modn1 w0_op.(znz_digits) w0_op.(znz_0)
+ w0_op.(znz_head0) w0_op.(znz_add_mul_div) w0_op.(znz_div21).
+ Definition w1_modn1 :=
+ gen_modn1 w1_op.(znz_digits) w1_op.(znz_0)
+ w1_op.(znz_head0) w1_op.(znz_add_mul_div) w1_op.(znz_div21).
+ Definition w2_modn1 :=
+ gen_modn1 w2_op.(znz_digits) w2_op.(znz_0)
+ w2_op.(znz_head0) w2_op.(znz_add_mul_div) w2_op.(znz_div21).
+ Definition w3_modn1 :=
+ gen_modn1 w3_op.(znz_digits) w3_op.(znz_0)
+ w3_op.(znz_head0) w3_op.(znz_add_mul_div) w3_op.(znz_div21).
+ Definition w4_modn1 :=
+ gen_modn1 w4_op.(znz_digits) w4_op.(znz_0)
+ w4_op.(znz_head0) w4_op.(znz_add_mul_div) w4_op.(znz_div21).
+ Definition w5_modn1 :=
+ gen_modn1 w5_op.(znz_digits) w5_op.(znz_0)
+ w5_op.(znz_head0) w5_op.(znz_add_mul_div) w5_op.(znz_div21).
+ Definition w6_modn1 :=
+ gen_modn1 w6_op.(znz_digits) w6_op.(znz_0)
+ w6_op.(znz_head0) w6_op.(znz_add_mul_div) w6_op.(znz_div21).
+ Definition w7_modn1 :=
+ gen_modn1 w7_op.(znz_digits) w7_op.(znz_0)
+ w7_op.(znz_head0) w7_op.(znz_add_mul_div) w7_op.(znz_div21).
+ Definition w8_modn1 :=
+ gen_modn1 w8_op.(znz_digits) w8_op.(znz_0)
+ w8_op.(znz_head0) w8_op.(znz_add_mul_div) w8_op.(znz_div21).
+ Definition w9_modn1 :=
+ gen_modn1 w9_op.(znz_digits) w9_op.(znz_0)
+ w9_op.(znz_head0) w9_op.(znz_add_mul_div) w9_op.(znz_div21).
+ Definition w10_modn1 :=
+ gen_modn1 w10_op.(znz_digits) w10_op.(znz_0)
+ w10_op.(znz_head0) w10_op.(znz_add_mul_div) w10_op.(znz_div21).
+ Definition w11_modn1 :=
+ gen_modn1 w11_op.(znz_digits) w11_op.(znz_0)
+ w11_op.(znz_head0) w11_op.(znz_add_mul_div) w11_op.(znz_div21).
+ Definition w12_modn1 :=
+ gen_modn1 w12_op.(znz_digits) w12_op.(znz_0)
+ w12_op.(znz_head0) w12_op.(znz_add_mul_div) w12_op.(znz_div21).
+
+ Definition mod_gt x y :=
+ match x, y with
+ | N0 wx, N0 wy => reduce_0 (w0_mod_gt wx wy)
+ | N0 wx, N1 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 0 wx in
+ reduce_1 (w1_mod_gt wx' wy)
+ | N0 wx, N2 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 1 wx in
+ reduce_2 (w2_mod_gt wx' wy)
+ | N0 wx, N3 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 2 wx in
+ reduce_3 (w3_mod_gt wx' wy)
+ | N0 wx, N4 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 3 wx in
+ reduce_4 (w4_mod_gt wx' wy)
+ | N0 wx, N5 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 4 wx in
+ reduce_5 (w5_mod_gt wx' wy)
+ | N0 wx, N6 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 5 wx in
+ reduce_6 (w6_mod_gt wx' wy)
+ | N0 wx, N7 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 6 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N0 wx, N8 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 7 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N0 wx, N9 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 8 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N0 wx, N10 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 9 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N0 wx, N11 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 10 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N0 wx, N12 wy =>
+ let wx':= GenBase.extend w0_op.(znz_0W) 11 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N0 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w0_op.(znz_0W) 12 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N1 wx, N0 wy => reduce_0 (w0_modn1 1 wx wy)
+ | N1 wx, N1 wy => reduce_1 (w1_mod_gt wx wy)
+ | N1 wx, N2 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 0 wx in
+ reduce_2 (w2_mod_gt wx' wy)
+ | N1 wx, N3 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 1 wx in
+ reduce_3 (w3_mod_gt wx' wy)
+ | N1 wx, N4 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 2 wx in
+ reduce_4 (w4_mod_gt wx' wy)
+ | N1 wx, N5 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 3 wx in
+ reduce_5 (w5_mod_gt wx' wy)
+ | N1 wx, N6 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 4 wx in
+ reduce_6 (w6_mod_gt wx' wy)
+ | N1 wx, N7 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 5 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N1 wx, N8 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 6 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N1 wx, N9 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 7 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N1 wx, N10 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 8 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N1 wx, N11 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 9 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N1 wx, N12 wy =>
+ let wx':= GenBase.extend w1_op.(znz_0W) 10 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N1 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w1_op.(znz_0W) 11 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N2 wx, N0 wy => reduce_0 (w0_modn1 2 wx wy)
+ | N2 wx, N1 wy => reduce_1 (w1_modn1 1 wx wy)
+ | N2 wx, N2 wy => reduce_2 (w2_mod_gt wx wy)
+ | N2 wx, N3 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 0 wx in
+ reduce_3 (w3_mod_gt wx' wy)
+ | N2 wx, N4 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 1 wx in
+ reduce_4 (w4_mod_gt wx' wy)
+ | N2 wx, N5 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 2 wx in
+ reduce_5 (w5_mod_gt wx' wy)
+ | N2 wx, N6 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 3 wx in
+ reduce_6 (w6_mod_gt wx' wy)
+ | N2 wx, N7 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 4 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N2 wx, N8 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 5 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N2 wx, N9 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 6 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N2 wx, N10 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 7 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N2 wx, N11 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 8 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N2 wx, N12 wy =>
+ let wx':= GenBase.extend w2_op.(znz_0W) 9 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N2 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w2_op.(znz_0W) 10 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N3 wx, N0 wy => reduce_0 (w0_modn1 3 wx wy)
+ | N3 wx, N1 wy => reduce_1 (w1_modn1 2 wx wy)
+ | N3 wx, N2 wy => reduce_2 (w2_modn1 1 wx wy)
+ | N3 wx, N3 wy => reduce_3 (w3_mod_gt wx wy)
+ | N3 wx, N4 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 0 wx in
+ reduce_4 (w4_mod_gt wx' wy)
+ | N3 wx, N5 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 1 wx in
+ reduce_5 (w5_mod_gt wx' wy)
+ | N3 wx, N6 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 2 wx in
+ reduce_6 (w6_mod_gt wx' wy)
+ | N3 wx, N7 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 3 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N3 wx, N8 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 4 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N3 wx, N9 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 5 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N3 wx, N10 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 6 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N3 wx, N11 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 7 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N3 wx, N12 wy =>
+ let wx':= GenBase.extend w3_op.(znz_0W) 8 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N3 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w3_op.(znz_0W) 9 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N4 wx, N0 wy => reduce_0 (w0_modn1 4 wx wy)
+ | N4 wx, N1 wy => reduce_1 (w1_modn1 3 wx wy)
+ | N4 wx, N2 wy => reduce_2 (w2_modn1 2 wx wy)
+ | N4 wx, N3 wy => reduce_3 (w3_modn1 1 wx wy)
+ | N4 wx, N4 wy => reduce_4 (w4_mod_gt wx wy)
+ | N4 wx, N5 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 0 wx in
+ reduce_5 (w5_mod_gt wx' wy)
+ | N4 wx, N6 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 1 wx in
+ reduce_6 (w6_mod_gt wx' wy)
+ | N4 wx, N7 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 2 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N4 wx, N8 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 3 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N4 wx, N9 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 4 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N4 wx, N10 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 5 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N4 wx, N11 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 6 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N4 wx, N12 wy =>
+ let wx':= GenBase.extend w4_op.(znz_0W) 7 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N4 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w4_op.(znz_0W) 8 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N5 wx, N0 wy => reduce_0 (w0_modn1 5 wx wy)
+ | N5 wx, N1 wy => reduce_1 (w1_modn1 4 wx wy)
+ | N5 wx, N2 wy => reduce_2 (w2_modn1 3 wx wy)
+ | N5 wx, N3 wy => reduce_3 (w3_modn1 2 wx wy)
+ | N5 wx, N4 wy => reduce_4 (w4_modn1 1 wx wy)
+ | N5 wx, N5 wy => reduce_5 (w5_mod_gt wx wy)
+ | N5 wx, N6 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 0 wx in
+ reduce_6 (w6_mod_gt wx' wy)
+ | N5 wx, N7 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 1 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N5 wx, N8 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 2 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N5 wx, N9 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 3 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N5 wx, N10 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 4 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N5 wx, N11 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 5 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N5 wx, N12 wy =>
+ let wx':= GenBase.extend w5_op.(znz_0W) 6 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N5 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w5_op.(znz_0W) 7 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N6 wx, N0 wy => reduce_0 (w0_modn1 6 wx wy)
+ | N6 wx, N1 wy => reduce_1 (w1_modn1 5 wx wy)
+ | N6 wx, N2 wy => reduce_2 (w2_modn1 4 wx wy)
+ | N6 wx, N3 wy => reduce_3 (w3_modn1 3 wx wy)
+ | N6 wx, N4 wy => reduce_4 (w4_modn1 2 wx wy)
+ | N6 wx, N5 wy => reduce_5 (w5_modn1 1 wx wy)
+ | N6 wx, N6 wy => reduce_6 (w6_mod_gt wx wy)
+ | N6 wx, N7 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 0 wx in
+ reduce_7 (w7_mod_gt wx' wy)
+ | N6 wx, N8 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 1 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N6 wx, N9 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 2 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N6 wx, N10 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 3 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N6 wx, N11 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 4 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N6 wx, N12 wy =>
+ let wx':= GenBase.extend w6_op.(znz_0W) 5 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N6 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w6_op.(znz_0W) 6 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N7 wx, N0 wy => reduce_0 (w0_modn1 7 wx wy)
+ | N7 wx, N1 wy => reduce_1 (w1_modn1 6 wx wy)
+ | N7 wx, N2 wy => reduce_2 (w2_modn1 5 wx wy)
+ | N7 wx, N3 wy => reduce_3 (w3_modn1 4 wx wy)
+ | N7 wx, N4 wy => reduce_4 (w4_modn1 3 wx wy)
+ | N7 wx, N5 wy => reduce_5 (w5_modn1 2 wx wy)
+ | N7 wx, N6 wy => reduce_6 (w6_modn1 1 wx wy)
+ | N7 wx, N7 wy => reduce_7 (w7_mod_gt wx wy)
+ | N7 wx, N8 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 0 wx in
+ reduce_8 (w8_mod_gt wx' wy)
+ | N7 wx, N9 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 1 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N7 wx, N10 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 2 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N7 wx, N11 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 3 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N7 wx, N12 wy =>
+ let wx':= GenBase.extend w7_op.(znz_0W) 4 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N7 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w7_op.(znz_0W) 5 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N8 wx, N0 wy => reduce_0 (w0_modn1 8 wx wy)
+ | N8 wx, N1 wy => reduce_1 (w1_modn1 7 wx wy)
+ | N8 wx, N2 wy => reduce_2 (w2_modn1 6 wx wy)
+ | N8 wx, N3 wy => reduce_3 (w3_modn1 5 wx wy)
+ | N8 wx, N4 wy => reduce_4 (w4_modn1 4 wx wy)
+ | N8 wx, N5 wy => reduce_5 (w5_modn1 3 wx wy)
+ | N8 wx, N6 wy => reduce_6 (w6_modn1 2 wx wy)
+ | N8 wx, N7 wy => reduce_7 (w7_modn1 1 wx wy)
+ | N8 wx, N8 wy => reduce_8 (w8_mod_gt wx wy)
+ | N8 wx, N9 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 0 wx in
+ reduce_9 (w9_mod_gt wx' wy)
+ | N8 wx, N10 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 1 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N8 wx, N11 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 2 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N8 wx, N12 wy =>
+ let wx':= GenBase.extend w8_op.(znz_0W) 3 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N8 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w8_op.(znz_0W) 4 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N9 wx, N0 wy => reduce_0 (w0_modn1 9 wx wy)
+ | N9 wx, N1 wy => reduce_1 (w1_modn1 8 wx wy)
+ | N9 wx, N2 wy => reduce_2 (w2_modn1 7 wx wy)
+ | N9 wx, N3 wy => reduce_3 (w3_modn1 6 wx wy)
+ | N9 wx, N4 wy => reduce_4 (w4_modn1 5 wx wy)
+ | N9 wx, N5 wy => reduce_5 (w5_modn1 4 wx wy)
+ | N9 wx, N6 wy => reduce_6 (w6_modn1 3 wx wy)
+ | N9 wx, N7 wy => reduce_7 (w7_modn1 2 wx wy)
+ | N9 wx, N8 wy => reduce_8 (w8_modn1 1 wx wy)
+ | N9 wx, N9 wy => reduce_9 (w9_mod_gt wx wy)
+ | N9 wx, N10 wy =>
+ let wx':= GenBase.extend w9_op.(znz_0W) 0 wx in
+ reduce_10 (w10_mod_gt wx' wy)
+ | N9 wx, N11 wy =>
+ let wx':= GenBase.extend w9_op.(znz_0W) 1 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N9 wx, N12 wy =>
+ let wx':= GenBase.extend w9_op.(znz_0W) 2 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N9 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w9_op.(znz_0W) 3 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N10 wx, N0 wy => reduce_0 (w0_modn1 10 wx wy)
+ | N10 wx, N1 wy => reduce_1 (w1_modn1 9 wx wy)
+ | N10 wx, N2 wy => reduce_2 (w2_modn1 8 wx wy)
+ | N10 wx, N3 wy => reduce_3 (w3_modn1 7 wx wy)
+ | N10 wx, N4 wy => reduce_4 (w4_modn1 6 wx wy)
+ | N10 wx, N5 wy => reduce_5 (w5_modn1 5 wx wy)
+ | N10 wx, N6 wy => reduce_6 (w6_modn1 4 wx wy)
+ | N10 wx, N7 wy => reduce_7 (w7_modn1 3 wx wy)
+ | N10 wx, N8 wy => reduce_8 (w8_modn1 2 wx wy)
+ | N10 wx, N9 wy => reduce_9 (w9_modn1 1 wx wy)
+ | N10 wx, N10 wy => reduce_10 (w10_mod_gt wx wy)
+ | N10 wx, N11 wy =>
+ let wx':= GenBase.extend w10_op.(znz_0W) 0 wx in
+ reduce_11 (w11_mod_gt wx' wy)
+ | N10 wx, N12 wy =>
+ let wx':= GenBase.extend w10_op.(znz_0W) 1 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N10 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w10_op.(znz_0W) 2 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N11 wx, N0 wy => reduce_0 (w0_modn1 11 wx wy)
+ | N11 wx, N1 wy => reduce_1 (w1_modn1 10 wx wy)
+ | N11 wx, N2 wy => reduce_2 (w2_modn1 9 wx wy)
+ | N11 wx, N3 wy => reduce_3 (w3_modn1 8 wx wy)
+ | N11 wx, N4 wy => reduce_4 (w4_modn1 7 wx wy)
+ | N11 wx, N5 wy => reduce_5 (w5_modn1 6 wx wy)
+ | N11 wx, N6 wy => reduce_6 (w6_modn1 5 wx wy)
+ | N11 wx, N7 wy => reduce_7 (w7_modn1 4 wx wy)
+ | N11 wx, N8 wy => reduce_8 (w8_modn1 3 wx wy)
+ | N11 wx, N9 wy => reduce_9 (w9_modn1 2 wx wy)
+ | N11 wx, N10 wy => reduce_10 (w10_modn1 1 wx wy)
+ | N11 wx, N11 wy => reduce_11 (w11_mod_gt wx wy)
+ | N11 wx, N12 wy =>
+ let wx':= GenBase.extend w11_op.(znz_0W) 0 wx in
+ reduce_12 (w12_mod_gt wx' wy)
+ | N11 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w11_op.(znz_0W) 1 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | N12 wx, N0 wy => reduce_0 (w0_modn1 12 wx wy)
+ | N12 wx, N1 wy => reduce_1 (w1_modn1 11 wx wy)
+ | N12 wx, N2 wy => reduce_2 (w2_modn1 10 wx wy)
+ | N12 wx, N3 wy => reduce_3 (w3_modn1 9 wx wy)
+ | N12 wx, N4 wy => reduce_4 (w4_modn1 8 wx wy)
+ | N12 wx, N5 wy => reduce_5 (w5_modn1 7 wx wy)
+ | N12 wx, N6 wy => reduce_6 (w6_modn1 6 wx wy)
+ | N12 wx, N7 wy => reduce_7 (w7_modn1 5 wx wy)
+ | N12 wx, N8 wy => reduce_8 (w8_modn1 4 wx wy)
+ | N12 wx, N9 wy => reduce_9 (w9_modn1 3 wx wy)
+ | N12 wx, N10 wy => reduce_10 (w10_modn1 2 wx wy)
+ | N12 wx, N11 wy => reduce_11 (w11_modn1 1 wx wy)
+ | N12 wx, N12 wy => reduce_12 (w12_mod_gt wx wy)
+ | N12 wx, Nn n wy =>
+ let wx':= extend n w12 (GenBase.extend w12_op.(znz_0W) 0 wx) in
+ reduce_n n ((make_op n).(znz_mod_gt) wx' wy)
+ | Nn n wx, N0 wy =>
+ let wy':= GenBase.extend w0_op.(znz_0W) 11 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N1 wy =>
+ let wy':= GenBase.extend w1_op.(znz_0W) 10 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N2 wy =>
+ let wy':= GenBase.extend w2_op.(znz_0W) 9 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N3 wy =>
+ let wy':= GenBase.extend w3_op.(znz_0W) 8 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N4 wy =>
+ let wy':= GenBase.extend w4_op.(znz_0W) 7 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N5 wy =>
+ let wy':= GenBase.extend w5_op.(znz_0W) 6 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N6 wy =>
+ let wy':= GenBase.extend w6_op.(znz_0W) 5 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N7 wy =>
+ let wy':= GenBase.extend w7_op.(znz_0W) 4 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N8 wy =>
+ let wy':= GenBase.extend w8_op.(znz_0W) 3 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N9 wy =>
+ let wy':= GenBase.extend w9_op.(znz_0W) 2 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N10 wy =>
+ let wy':= GenBase.extend w10_op.(znz_0W) 1 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N11 wy =>
+ let wy':= GenBase.extend w11_op.(znz_0W) 0 wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, N12 wy =>
+ let wy':= wy in
+ reduce_12 (w12_modn1 (S n) wx wy')
+ | Nn n wx, Nn m wy =>
+ match extend_to_max w12 n m wx wy with
+ | inl wx' =>
+ reduce_n m ((make_op m).(znz_mod_gt) wx' wy)
+ | inr wy' =>
+ reduce_n n ((make_op n).(znz_mod_gt) wx wy')
+ end
+ end.
+
+ Definition modulo x y :=
+ match compare x y with
+ | Eq => zero
+ | Lt => x
+ | Gt => mod_gt x y
+ end.
+
+ Definition digits x :=
+ match x with
+ | N0 _ => w0_op.(znz_digits)
+ | N1 _ => w1_op.(znz_digits)
+ | N2 _ => w2_op.(znz_digits)
+ | N3 _ => w3_op.(znz_digits)
+ | N4 _ => w4_op.(znz_digits)
+ | N5 _ => w5_op.(znz_digits)
+ | N6 _ => w6_op.(znz_digits)
+ | N7 _ => w7_op.(znz_digits)
+ | N8 _ => w8_op.(znz_digits)
+ | N9 _ => w9_op.(znz_digits)
+ | N10 _ => w10_op.(znz_digits)
+ | N11 _ => w11_op.(znz_digits)
+ | N12 _ => w12_op.(znz_digits)
+ | Nn n _ => (make_op n).(znz_digits)
+ end.
+
+ Definition gcd_gt_body a b cont :=
+ match compare b zero with
+ | Gt =>
+ let r := mod_gt a b in
+ match compare r zero with
+ | Gt => cont r (mod_gt b r)
+ | _ => b
+ end
+ | _ => a
+ end.
+
+ Fixpoint gcd_gt (p:positive) (cont:t->t->t) (a b:t) {struct p} : t :=
+ gcd_gt_body a b
+ (fun a b =>
+ match p with
+ | xH => cont a b
+ | xO p => gcd_gt p (gcd_gt p cont) a b
+ | xI p => gcd_gt p (gcd_gt p cont) a b
+ end).
+
+ Definition gcd_cont a b :=
+ match compare one b with
+ | Eq => one
+ | _ => a
+ end.
+
+ Definition gcd a b :=
+ match compare a b with
+ | Eq => a
+ | Lt => gcd_gt (digits b) gcd_cont b a
+ | Gt => gcd_gt (digits a) gcd_cont a b
+ end.
+
+ Definition of_pos x :=
+ let h := nat_of_P (pheight x) in
+ match h with
+ | O => reduce_0 (snd (w0_op.(znz_of_pos) x))
+ | (S O) => reduce_1 (snd (w1_op.(znz_of_pos) x))
+ | (S (S O)) => reduce_2 (snd (w2_op.(znz_of_pos) x))
+ | (S (S (S O))) => reduce_3 (snd (w3_op.(znz_of_pos) x))
+ | (S (S (S (S O)))) => reduce_4 (snd (w4_op.(znz_of_pos) x))
+ | (S (S (S (S (S O))))) => reduce_5 (snd (w5_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S O)))))) => reduce_6 (snd (w6_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S (S O))))))) => reduce_7 (snd (w7_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S (S (S O)))))))) => reduce_8 (snd (w8_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S (S (S (S O))))))))) => reduce_9 (snd (w9_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S (S (S (S (S O)))))))))) => reduce_10 (snd (w10_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S (S (S (S (S (S O))))))))))) => reduce_11 (snd (w11_op.(znz_of_pos) x))
+ | (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))) => reduce_12 (snd (w12_op.(znz_of_pos) x))
+ | _ =>
+ let n := minus h 13 in
+ reduce_n n (snd ((make_op n).(znz_of_pos) x))
+ end.
+
+ Definition of_N x :=
+ match x with
+ | BinNat.N0 => zero
+ | Npos p => of_pos p
+ end.
+
+ Definition to_Z x :=
+ match x with
+ | N0 wx => w0_op.(znz_to_Z) wx
+ | N1 wx => w1_op.(znz_to_Z) wx
+ | N2 wx => w2_op.(znz_to_Z) wx
+ | N3 wx => w3_op.(znz_to_Z) wx
+ | N4 wx => w4_op.(znz_to_Z) wx
+ | N5 wx => w5_op.(znz_to_Z) wx
+ | N6 wx => w6_op.(znz_to_Z) wx
+ | N7 wx => w7_op.(znz_to_Z) wx
+ | N8 wx => w8_op.(znz_to_Z) wx
+ | N9 wx => w9_op.(znz_to_Z) wx
+ | N10 wx => w10_op.(znz_to_Z) wx
+ | N11 wx => w11_op.(znz_to_Z) wx
+ | N12 wx => w12_op.(znz_to_Z) wx
+ | Nn n wx => (make_op n).(znz_to_Z) wx
+ end.
+
+End Make.
+
diff --git a/theories/Ints/num/Nbasic.v b/theories/Ints/num/Nbasic.v
new file mode 100644
index 0000000000..23229b52ca
--- /dev/null
+++ b/theories/Ints/num/Nbasic.v
@@ -0,0 +1,147 @@
+Require Import ZArith.
+Require Import Basic_type.
+
+
+Definition zn2z_word_comm : forall w n, zn2z (word w n) = word (zn2z w) n.
+ fix zn2z_word_comm 2.
+ intros w n; case n.
+ reflexivity.
+ intros n0;simpl.
+ case (zn2z_word_comm w n0).
+ reflexivity.
+Defined.
+
+Fixpoint extend (n:nat) {struct n} : forall w:Set, zn2z w -> word w (S n) :=
+ match n return forall w:Set, zn2z w -> word w (S n) with
+ | O => fun w x => x
+ | S m =>
+ let aux := extend m in
+ fun w x => WW W0 (aux w x)
+ end.
+
+Section ExtendMax.
+
+ Variable w:Set.
+
+ Definition Tmax n m :=
+ ( {p:nat| word (word w n) p = word w m}
+ + {p:nat| word (word w m) p = word w n})%type.
+
+ Definition max : forall n m, Tmax n m.
+ fix max 1;intros n.
+ case n.
+ intros m;left;exists m;exact (refl_equal (word w m)).
+ intros n0 m;case m.
+ right;exists (S n0);exact (refl_equal (word w (S n0))).
+ intros m0;case (max n0 m0);intros H;case H;intros p Heq.
+ left;exists p;simpl.
+ case (zn2z_word_comm (word w n0) p).
+ case Heq.
+ exact (refl_equal (zn2z (word (word w n0) p))).
+ right;exists p;simpl.
+ case (zn2z_word_comm (word w m0) p).
+ case Heq.
+ exact (refl_equal (zn2z (word (word w m0) p))).
+ Defined.
+
+ Definition extend_to_max :
+ forall n m (x:zn2z (word w n)) (y:zn2z (word w m)),
+ (zn2z (word w m) + zn2z (word w n))%type.
+ intros n m x y.
+ case (max n m);intros (p, Heq);case Heq.
+ left;exact (extend p (word w n) x).
+ right;exact (extend p (word w m) y).
+ Defined.
+
+End ExtendMax.
+
+Section Reduce.
+
+ Variable w : Set.
+ Variable nT : Set.
+ Variable N0 : nT.
+ Variable eq0 : w -> bool.
+ Variable reduce_n : w -> nT.
+ Variable zn2z_to_Nt : zn2z w -> nT.
+
+ Definition reduce_n1 (x:zn2z w) :=
+ match x with
+ | W0 => N0
+ | WW xh xl =>
+ if eq0 xh then reduce_n xl
+ else zn2z_to_Nt x
+ end.
+
+End Reduce.
+
+Section ReduceRec.
+
+ Variable w : Set.
+ Variable nT : Set.
+ Variable N0 : nT.
+ Variable reduce_1n : zn2z w -> nT.
+ Variable c : forall n, word w (S n) -> nT.
+
+ Fixpoint reduce_n (n:nat) : word w (S n) -> nT :=
+ match n return word w (S n) -> nT with
+ | O => reduce_1n
+ | S m => fun x =>
+ match x with
+ | W0 => N0
+ | WW xh xl =>
+ match xh with
+ | W0 => @reduce_n m xl
+ | _ => @c (S m) x
+ end
+ end
+ end.
+
+End ReduceRec.
+
+Definition opp_compare cmp :=
+ match cmp with
+ | Lt => Gt
+ | Eq => Eq
+ | Gt => Lt
+ end.
+
+Section CompareRec.
+
+ Variable wm w : Set.
+ Variable w_0 : w.
+ Variable compare : w -> w -> comparison.
+ Variable compare0_m : wm -> comparison.
+ Variable compare_m : wm -> w -> comparison.
+
+ Fixpoint compare0_mn (n:nat) : word wm n -> comparison :=
+ match n return word wm n -> comparison with
+ | 0 => compare0_m
+ | S m => fun x =>
+ match x with
+ | W0 => Eq
+ | WW xh xl =>
+ match compare0_mn m xh with
+ | Eq => compare0_mn m xl
+ | r => Lt
+ end
+ end
+ end.
+
+ Fixpoint compare_mn_1 (n:nat) : word wm n -> w -> comparison :=
+ match n return word wm n -> w -> comparison with
+ | 0 => compare_m
+ | S m => fun x y =>
+ match x with
+ | W0 => compare w_0 y
+ | WW xh xl =>
+ match compare0_mn m xh with
+ | Eq => compare_mn_1 m xl y
+ | r => Gt
+ end
+ end
+ end.
+
+End CompareRec.
+
+
+
diff --git a/theories/Ints/num/QMake.v b/theories/Ints/num/QMake.v
new file mode 100644
index 0000000000..28f4bd991b
--- /dev/null
+++ b/theories/Ints/num/QMake.v
@@ -0,0 +1,899 @@
+Require Import Bool.
+Require Import ZArith.
+Require Import Arith.
+
+Inductive q_type : Set :=
+ | Qz : Z.t -> q_type
+ | Qq : Z.t -> N.t -> q_type.
+
+Definition print_type x :=
+ match x with
+ | Qz _ => Z
+ | _ => (Z*Z)%type
+ end.
+
+Definition print x :=
+ match x return print_type x with
+ | Qz zx => Z.to_Z zx
+ | Qq nx dx => (Z.to_Z nx, N.to_Z dx)
+ end.
+
+Module Qp.
+
+ Definition t := q_type.
+
+ Definition zero := Qz Z.zero.
+ Definition one := Qz Z.one.
+ Definition minus_one := Qz Z.minus_one.
+
+ Definition of_Z x := Qz (Z.of_Z x).
+
+ Definition d_to_Z d := Z.Pos (N.succ d).
+
+ Definition compare x y :=
+ match x, y with
+ | Qz zx, Qz zy => Z.compare zx zy
+ | Qz zx, Qq ny dy => Z.compare (Z.mul zx (d_to_Z dy)) ny
+ | Qq nx dy, Qz zy => Z.compare nx (Z.mul zy (d_to_Z dy))
+ | Qq nx dx, Qq ny dy =>
+ Z.compare (Z.mul nx (d_to_Z dy)) (Z.mul ny (d_to_Z dx))
+ end.
+
+ Definition opp x :=
+ match x with
+ | Qz zx => Qz (Z.opp zx)
+ | Qq nx dx => Qq (Z.opp nx) dx
+ end.
+
+(* Inv d > 0, Pour la forme normal unique on veut d > 1 *)
+ Definition norm n d :=
+ if Z.eq_bool n Z.zero then zero
+ else
+ let gcd := N.gcd (Z.to_N n) d in
+ if N.eq_bool gcd N.one then Qq n (N.pred d)
+ else
+ let n := Z.div n (Z.Pos gcd) in
+ let d := N.div d gcd in
+ if N.eq_bool d N.one then Qz n
+ else Qq n (N.pred d).
+
+ Definition add x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.add zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.add (Z.mul zx (d_to_Z dy)) ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.add nx (Z.mul zy (d_to_Z dx))) dx
+ | Qq nx dx, Qq ny dy =>
+ let dx' := N.succ dx in
+ let dy' := N.succ dy in
+ let n := Z.add (Z.mul nx (Z.Pos dy')) (Z.mul ny (Z.Pos dx')) in
+ let d := N.pred (N.mul dx' dy') in
+ Qq n d
+ end.
+
+ Definition add_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.add zx zy)
+ | Qz zx, Qq ny dy =>
+ let d := N.succ dy in
+ norm (Z.add (Z.mul zx (Z.Pos d)) ny) d
+ | Qq nx dx, Qz zy =>
+ let d := N.succ dx in
+ norm (Z.add (Z.mul zy (Z.Pos d)) nx) d
+ | Qq nx dx, Qq ny dy =>
+ let dx' := N.succ dx in
+ let dy' := N.succ dy in
+ let n := Z.add (Z.mul nx (Z.Pos dy')) (Z.mul ny (Z.Pos dx')) in
+ let d := N.mul dx' dy' in
+ norm n d
+ end.
+
+ Definition sub x y := add x (opp y).
+
+ Definition sub_norm x y := add_norm x (opp y).
+
+ Definition mul x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.mul zx ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.mul nx zy) dx
+ | Qq nx dx, Qq ny dy =>
+ Qq (Z.mul nx ny) (N.pred (N.mul (N.succ dx) (N.succ dy)))
+ end.
+
+ Definition mul_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy =>
+ if Z.eq_bool zx Z.zero then zero
+ else
+ let d := N.succ dy in
+ let gcd := N.gcd (Z.to_N zx) d in
+ if N.eq_bool gcd N.one then Qq (Z.mul zx ny) dy
+ else
+ let zx := Z.div zx (Z.Pos gcd) in
+ let d := N.div d gcd in
+ if N.eq_bool d N.one then Qz (Z.mul zx ny)
+ else Qq (Z.mul zx ny) (N.pred d)
+ | Qq nx dx, Qz zy =>
+ if Z.eq_bool zy Z.zero then zero
+ else
+ let d := N.succ dx in
+ let gcd := N.gcd (Z.to_N zy) d in
+ if N.eq_bool gcd N.one then Qq (Z.mul zy nx) dx
+ else
+ let zy := Z.div zy (Z.Pos gcd) in
+ let d := N.div d gcd in
+ if N.eq_bool d N.one then Qz (Z.mul zy nx)
+ else Qq (Z.mul zy nx) (N.pred d)
+ | Qq nx dx, Qq ny dy =>
+ norm (Z.mul nx ny) (N.mul (N.succ dx) (N.succ dy))
+ end.
+
+ Definition inv x :=
+ match x with
+ | Qz (Z.Pos n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.one (N.pred n)
+ | Qz (Z.Neg n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.minus_one (N.pred n)
+ | Qq (Z.Pos n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Pos (N.succ d)) (N.pred n)
+ | Qq (Z.Neg n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Neg (N.succ d)) (N.pred n)
+ end.
+
+Definition inv_norm x :=
+ match x with
+ | Qz (Z.Pos n) =>
+ if N.eq_bool n N.zero then zero else
+ if N.eq_bool n N.one then x else Qq Z.one (N.pred n)
+ | Qz (Z.Neg n) =>
+ if N.eq_bool n N.zero then zero else
+ if N.eq_bool n N.one then x else Qq Z.minus_one n
+ | Qq (Z.Pos n) d => let d := N.succ d in
+ if N.eq_bool n N.one then Qz (Z.Pos d)
+ else Qq (Z.Pos d) (N.pred n)
+ | Qq (Z.Neg n) d => let d := N.succ d in
+ if N.eq_bool n N.one then Qz (Z.Neg d)
+ else Qq (Z.Pos d) (N.pred n)
+ end.
+
+
+ Definition square x :=
+ match x with
+ | Qz zx => Qz (Z.square zx)
+ | Qq nx dx => Qq (Z.square nx) (N.pred (N.square (N.succ dx)))
+ end.
+
+ Definition power_pos x p :=
+ match x with
+ | Qz zx => Qz (Z.power_pos zx p)
+ | Qq nx dx => Qq (Z.power_pos nx p) (N.pred (N.power_pos (N.succ dx) p))
+ end.
+
+End Qp.
+
+
+Module Qv.
+
+ (* /!\ Invariant maintenu par les fonctions :
+ - le denominateur n'est jamais nul *)
+
+ Definition t := q_type.
+
+ Definition zero := Qz Z.zero.
+ Definition one := Qz Z.one.
+ Definition minus_one := Qz Z.minus_one.
+
+ Definition of_Z x := Qz (Z.of_Z x).
+
+ Definition is_valid x :=
+ match x with
+ | Qz _ => True
+ | Qq n d => if N.eq_bool d N.zero then False else True
+ end.
+ (* Les fonctions doivent assurer que si leur arguments sont valides alors
+ le resultat est correct et valide (si c'est un Q)
+ *)
+
+ Definition compare x y :=
+ match x, y with
+ | Qz zx, Qz zy => Z.compare zx zy
+ | Qz zx, Qq ny dy => Z.compare (Z.mul zx (Z.Pos dy)) ny
+ | Qq nx dx, Qz zy => Z.compare Z.zero zy
+ | Qq nx dx, Qq ny dy => Z.compare (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx))
+ end.
+
+ Definition opp x :=
+ match x with
+ | Qz zx => Qz (Z.opp zx)
+ | Qq nx dx => Qq (Z.opp nx) dx
+ end.
+
+ Definition norm n d :=
+ if Z.eq_bool n Z.zero then zero
+ else
+ let gcd := N.gcd (Z.to_N n) d in
+ if N.eq_bool gcd N.one then Qq n d
+ else
+ let n := Z.div n (Z.Pos gcd) in
+ let d := N.div d gcd in
+ if N.eq_bool d N.one then Qz n
+ else Qq n d.
+
+ Definition add x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.add zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq nx dx, Qq ny dy =>
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ Qq n d
+ end.
+
+ Definition add_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.add zx zy)
+ | Qz zx, Qq ny dy =>
+ norm (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ | Qq nx dx, Qz zy =>
+ norm (Z.add (Z.mul zy (Z.Pos dx)) nx) dx
+ | Qq nx dx, Qq ny dy =>
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ norm n d
+ end.
+
+ Definition sub x y := add x (opp y).
+
+ Definition sub_norm x y := add_norm x (opp y).
+
+ Definition mul x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.mul zx ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.mul nx zy) dx
+ | Qq nx dx, Qq ny dy =>
+ Qq (Z.mul nx ny) (N.mul dx dy)
+ end.
+
+ Definition mul_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy =>
+ if Z.eq_bool zx Z.zero then zero
+ else
+ let gcd := N.gcd (Z.to_N zx) dy in
+ if N.eq_bool gcd N.one then Qq (Z.mul zx ny) dy
+ else
+ let zx := Z.div zx (Z.Pos gcd) in
+ let d := N.div dy gcd in
+ if N.eq_bool d N.one then Qz (Z.mul zx ny)
+ else Qq (Z.mul zx ny) d
+ | Qq nx dx, Qz zy =>
+ if Z.eq_bool zy Z.zero then zero
+ else
+ let gcd := N.gcd (Z.to_N zy) dx in
+ if N.eq_bool gcd N.one then Qq (Z.mul zy nx) dx
+ else
+ let zy := Z.div zy (Z.Pos gcd) in
+ let d := N.div dx gcd in
+ if N.eq_bool d N.one then Qz (Z.mul zy nx)
+ else Qq (Z.mul zy nx) d
+ | Qq nx dx, Qq ny dy => norm (Z.mul nx ny) (N.mul dx dy)
+ end.
+
+ Definition inv x :=
+ match x with
+ | Qz (Z.Pos n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.one n
+ | Qz (Z.Neg n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.minus_one n
+ | Qq (Z.Pos n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Pos d) n
+ | Qq (Z.Neg n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Neg d) n
+ end.
+
+ Definition square x :=
+ match x with
+ | Qz zx => Qz (Z.square zx)
+ | Qq nx dx => Qq (Z.square nx) (N.square dx)
+ end.
+
+ Definition power_pos x p :=
+ match x with
+ | Qz zx => Qz (Z.power_pos zx p)
+ | Qq nx dx => Qq (Z.power_pos nx p) (N.power_pos dx p)
+ end.
+
+End Qv.
+
+Module Q.
+
+ (* Troisieme solution :
+ 0 a de nombreuse representation :
+ 0, -0, 1/0, ... n/0,
+ il faut alors faire attention avec la comparaison et l'addition
+ *)
+
+ Definition t := q_type.
+
+ Definition zero := Qz Z.zero.
+ Definition one := Qz Z.one.
+ Definition minus_one := Qz Z.minus_one.
+
+ Definition of_Z x := Qz (Z.of_Z x).
+
+ Definition compare x y :=
+ match x, y with
+ | Qz zx, Qz zy => Z.compare zx zy
+ | Qz zx, Qq ny dy =>
+ if N.eq_bool dy N.zero then Z.compare zx Z.zero
+ else Z.compare (Z.mul zx (Z.Pos dy)) ny
+ | Qq nx dx, Qz zy =>
+ if N.eq_bool dx N.zero then Z.compare Z.zero zy
+ else Z.compare nx (Z.mul zy (Z.Pos dx))
+ | Qq nx dx, Qq ny dy =>
+ match N.eq_bool dx N.zero, N.eq_bool dy N.zero with
+ | true, true => Eq
+ | true, false => Z.compare Z.zero ny
+ | false, true => Z.compare nx Z.zero
+ | false, false => Z.compare (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx))
+ end
+ end.
+
+ Definition opp x :=
+ match x with
+ | Qz zx => Qz (Z.opp zx)
+ | Qq nx dx => Qq (Z.opp nx) dx
+ end.
+
+(* Je pense que cette fonction normalise bien ... *)
+ Definition norm n d :=
+ let gcd := N.gcd (Z.to_N n) d in
+ match N.compare N.one gcd with
+ | Lt =>
+ let n := Z.div n (Z.Pos gcd) in
+ let d := N.div d gcd in
+ match N.compare d N.one with
+ | Gt => Qq n d
+ | Eq => Qz n
+ | Lt => zero
+ end
+ | Eq => Qq n d
+ | Gt => zero (* gcd = 0 => both numbers are 0 *)
+ end.
+
+ Definition add x y :=
+ match x with
+ | Qz zx =>
+ match y with
+ | Qz zy => Qz (Z.add zx zy)
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else Qq (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ end
+ | Qq nx dx =>
+ if N.eq_bool dx N.zero then y
+ else match y with
+ | Qz zy => Qq (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ Qq n d
+ end
+ end.
+
+ Definition add_norm x y :=
+ match x with
+ | Qz zx =>
+ match y with
+ | Qz zy => Qz (Z.add zx zy)
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else norm (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ end
+ | Qq nx dx =>
+ if N.eq_bool dx N.zero then y
+ else match y with
+ | Qz zy => norm (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ norm n d
+ end
+ end.
+
+ Definition sub x y := add x (opp y).
+
+ Definition sub_norm x y := add_norm x (opp y).
+
+ Definition mul x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.mul zx ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.mul nx zy) dx
+ | Qq nx dx, Qq ny dy => Qq (Z.mul nx ny) (N.mul dx dy)
+ end.
+
+Definition mul_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy =>
+ if Z.eq_bool zx Z.zero then zero
+ else
+ let d := N.succ dy in
+ let gcd := N.gcd (Z.to_N zx) d in
+ if N.eq_bool gcd N.one then Qq (Z.mul zx ny) dy
+ else
+ let zx := Z.div zx (Z.Pos gcd) in
+ let d := N.div d gcd in
+ if N.eq_bool d N.one then Qz (Z.mul zx ny)
+ else Qq (Z.mul zx ny) (N.pred d)
+ | Qq nx dx, Qz zy =>
+ if Z.eq_bool zy Z.zero then zero
+ else
+ let d := N.succ dx in
+ let gcd := N.gcd (Z.to_N zy) d in
+ if N.eq_bool gcd N.one then Qq (Z.mul zy nx) dx
+ else
+ let zy := Z.div zy (Z.Pos gcd) in
+ let d := N.div d gcd in
+ if N.eq_bool d N.one then Qz (Z.mul zy nx)
+ else Qq (Z.mul zy nx) (N.pred d)
+ | Qq nx dx, Qq ny dy =>
+ let dx := N.succ dx in
+ let dy := N.succ dy in
+ let (nx, dy) :=
+ let gcd := N.gcd (Z.to_N nx) dy in
+ if N.eq_bool gcd N.one then (nx, dy)
+ else (Z.div nx (Z.Pos gcd), N.div dy gcd) in
+ let (ny, dx) :=
+ let gcd := N.gcd (Z.to_N ny) dx in
+ if N.eq_bool gcd N.one then (ny, dx)
+ else (Z.div ny (Z.Pos gcd), N.div dx gcd) in
+ let d := (N.mul dx dy) in
+ if N.eq_bool d N.one then Qz (Z.mul ny nx)
+ else Qq (Z.mul ny nx) (N.pred d)
+ end.
+
+
+Definition inv x :=
+ match x with
+ | Qz (Z.Pos n) => Qq Z.one (N.pred n)
+ | Qz (Z.Neg n) => Qq Z.minus_one (N.pred n)
+ | Qq (Z.Pos n) d => Qq (Z.Pos (N.succ d)) (N.pred n)
+ | Qq (Z.Neg n) d => Qq (Z.Neg (N.succ d)) (N.pred n)
+ end.
+
+
+Definition inv_norm x :=
+ match x with
+ | Qz (Z.Pos n) => if N.eq_bool n N.one then x else Qq Z.one (N.pred n)
+ | Qz (Z.Neg n) => if N.eq_bool n N.one then x else Qq Z.minus_one n
+ | Qq (Z.Pos n) d => let d := N.succ d in
+ if N.eq_bool n N.one then Qz (Z.Pos d)
+ else Qq (Z.Pos d) (N.pred n)
+ | Qq (Z.Neg n) d => let d := N.succ d in
+ if N.eq_bool n N.one then Qz (Z.Neg d)
+ else Qq (Z.Pos d) (N.pred n)
+ end.
+
+ Definition square x :=
+ match x with
+ | Qz zx => Qz (Z.square zx)
+ | Qq nx dx => Qq (Z.square nx) (N.square dx)
+ end.
+
+ Definition power_pos x p :=
+ match x with
+ | Qz zx => Qz (Z.power_pos zx p)
+ | Qq nx dx => Qq (Z.power_pos nx p) (N.power_pos dx p)
+ end.
+
+End Q.
+
+Module Qif.
+
+ (* Troisieme solution :
+ 0 a de nombreuse representation :
+ 0, -0, 1/0, ... n/0,
+ il faut alors faire attention avec la comparaison et l'addition
+
+ Les fonctions de normalization s'effectue seulement si les
+ nombres sont grands.
+ *)
+
+ Definition t := q_type.
+
+ Definition zero := Qz Z.zero.
+ Definition one := Qz Z.one.
+ Definition minus_one := Qz Z.minus_one.
+
+ Definition of_Z x := Qz (Z.of_Z x).
+
+ Definition compare x y :=
+ match x, y with
+ | Qz zx, Qz zy => Z.compare zx zy
+ | Qz zx, Qq ny dy =>
+ if N.eq_bool dy N.zero then Z.compare zx Z.zero
+ else Z.compare (Z.mul zx (Z.Pos dy)) ny
+ | Qq nx dx, Qz zy =>
+ if N.eq_bool dx N.zero then Z.compare Z.zero zy
+ else Z.compare nx (Z.mul zy (Z.Pos dx))
+ | Qq nx dx, Qq ny dy =>
+ match N.eq_bool dx N.zero, N.eq_bool dy N.zero with
+ | true, true => Eq
+ | true, false => Z.compare Z.zero ny
+ | false, true => Z.compare nx Z.zero
+ | false, false => Z.compare (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx))
+ end
+ end.
+
+ Definition opp x :=
+ match x with
+ | Qz zx => Qz (Z.opp zx)
+ | Qq nx dx => Qq (Z.opp nx) dx
+ end.
+
+
+ Definition do_norm_n n :=
+ match n with
+ | N.N0 _ => false
+ | N.N1 _ => false
+ | N.N2 _ => false
+ | N.N3 _ => false
+ | N.N4 _ => false
+ | N.N5 _ => false
+ | N.N6 _ => false
+ | N.N7 _ => false
+ | N.N8 _ => false
+ | N.N9 _ => true
+ | N.N10 _ => true
+ | N.N11 _ => true
+ | N.N12 _ => true
+ | N.Nn n _ => true
+ end.
+
+ Definition do_norm_z z :=
+ match z with
+ | Z.Pos n => do_norm_n n
+ | Z.Neg n => do_norm_n n
+ end.
+
+Require Import Bool.
+(* Je pense que cette fonction normalise bien ... *)
+ Definition norm n d :=
+ if andb (do_norm_z n) (do_norm_n d) then
+ let gcd := N.gcd (Z.to_N n) d in
+ match N.compare N.one gcd with
+ | Lt =>
+ let n := Z.div n (Z.Pos gcd) in
+ let d := N.div d gcd in
+ match N.compare d N.one with
+ | Gt => Qq n d
+ | Eq => Qz n
+ | Lt => zero
+ end
+ | Eq => Qq n d
+ | Gt => zero (* gcd = 0 => both numbers are 0 *)
+ end
+ else Qq n d.
+
+
+
+ Definition add x y :=
+ match x with
+ | Qz zx =>
+ match y with
+ | Qz zy => Qz (Z.add zx zy)
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else Qq (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ end
+ | Qq nx dx =>
+ if N.eq_bool dx N.zero then y
+ else match y with
+ | Qz zy => Qq (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ Qq n d
+ end
+ end.
+
+ Definition add_norm x y :=
+ match x with
+ | Qz zx =>
+ match y with
+ | Qz zy => Qz (Z.add zx zy)
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else norm (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ end
+ | Qq nx dx =>
+ if N.eq_bool dx N.zero then y
+ else match y with
+ | Qz zy => norm (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ norm n d
+ end
+ end.
+
+ Definition sub x y := add x (opp y).
+
+ Definition sub_norm x y := add_norm x (opp y).
+
+ Definition mul x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.mul zx ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.mul nx zy) dx
+ | Qq nx dx, Qq ny dy => Qq (Z.mul nx ny) (N.mul dx dy)
+ end.
+
+ Definition mul_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => norm (Z.mul zx ny) dy
+ | Qq nx dx, Qz zy => norm (Z.mul nx zy) dx
+ | Qq nx dx, Qq ny dy => norm (Z.mul nx ny) (N.mul dx dy)
+ end.
+
+ Definition inv x :=
+ match x with
+ | Qz (Z.Pos n) => Qq Z.one n
+ | Qz (Z.Neg n) => Qq Z.minus_one n
+ | Qq (Z.Pos n) d => Qq (Z.Pos d) n
+ | Qq (Z.Neg n) d => Qq (Z.Neg d) n
+ end.
+
+ Definition inv_norm x :=
+ match x with
+ | Qz (Z.Pos n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.one n
+ | Qz (Z.Neg n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.minus_one n
+ | Qq (Z.Pos n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Pos d) n
+ | Qq (Z.Neg n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Neg d) n
+ end.
+
+ Definition square x :=
+ match x with
+ | Qz zx => Qz (Z.square zx)
+ | Qq nx dx => Qq (Z.square nx) (N.square dx)
+ end.
+
+ Definition power_pos x p :=
+ match x with
+ | Qz zx => Qz (Z.power_pos zx p)
+ | Qq nx dx => Qq (Z.power_pos nx p) (N.power_pos dx p)
+ end.
+
+End Qif.
+
+Module Qbi.
+
+ (* Troisieme solution :
+ 0 a de nombreuse representation :
+ 0, -0, 1/0, ... n/0,
+ il faut alors faire attention avec la comparaison et l'addition
+
+ Les fonctions de normalization s'effectue seulement si les
+ nombres sont grands.
+ *)
+
+ Definition t := q_type.
+
+ Definition zero := Qz Z.zero.
+ Definition one := Qz Z.one.
+ Definition minus_one := Qz Z.minus_one.
+
+ Definition of_Z x := Qz (Z.of_Z x).
+
+ Definition compare x y :=
+ match x, y with
+ | Qz zx, Qz zy => Z.compare zx zy
+ | Qz zx, Qq ny dy =>
+ if N.eq_bool dy N.zero then Z.compare zx Z.zero
+ else
+ match Z.cmp_sign zx ny with
+ | Lt => Lt
+ | Gt => Gt
+ | Eq => Z.compare (Z.mul zx (Z.Pos dy)) ny
+ end
+ | Qq nx dx, Qz zy =>
+ if N.eq_bool dx N.zero then Z.compare Z.zero zy
+ else
+ match Z.cmp_sign nx zy with
+ | Lt => Lt
+ | Gt => Gt
+ | Eq => Z.compare nx (Z.mul zy (Z.Pos dx))
+ end
+ | Qq nx dx, Qq ny dy =>
+ match N.eq_bool dx N.zero, N.eq_bool dy N.zero with
+ | true, true => Eq
+ | true, false => Z.compare Z.zero ny
+ | false, true => Z.compare nx Z.zero
+ | false, false =>
+ match Z.cmp_sign nx ny with
+ | Lt => Lt
+ | Gt => Gt
+ | Eq => Z.compare (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx))
+ end
+ end
+ end.
+
+ Definition opp x :=
+ match x with
+ | Qz zx => Qz (Z.opp zx)
+ | Qq nx dx => Qq (Z.opp nx) dx
+ end.
+
+
+ Definition do_norm_n n :=
+ match n with
+ | N.N0 _ => false
+ | N.N1 _ => false
+ | N.N2 _ => false
+ | N.N3 _ => false
+ | N.N4 _ => false
+ | N.N5 _ => false
+ | N.N6 _ => false
+ | N.N7 _ => false
+ | N.N8 _ => false
+ | N.N9 _ => true
+ | N.N10 _ => true
+ | N.N11 _ => true
+ | N.N12 _ => true
+ | N.Nn n _ => true
+ end.
+
+ Definition do_norm_z z :=
+ match z with
+ | Z.Pos n => do_norm_n n
+ | Z.Neg n => do_norm_n n
+ end.
+
+(* Je pense que cette fonction normalise bien ... *)
+ Definition norm n d :=
+ if andb (do_norm_z n) (do_norm_n d) then
+ let gcd := N.gcd (Z.to_N n) d in
+ match N.compare N.one gcd with
+ | Lt =>
+ let n := Z.div n (Z.Pos gcd) in
+ let d := N.div d gcd in
+ match N.compare d N.one with
+ | Gt => Qq n d
+ | Eq => Qz n
+ | Lt => zero
+ end
+ | Eq => Qq n d
+ | Gt => zero (* gcd = 0 => both numbers are 0 *)
+ end
+ else Qq n d.
+
+
+ Definition add x y :=
+ match x with
+ | Qz zx =>
+ match y with
+ | Qz zy => Qz (Z.add zx zy)
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else Qq (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ end
+ | Qq nx dx =>
+ if N.eq_bool dx N.zero then y
+ else match y with
+ | Qz zy => Qq (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ if N.eq_bool dx dy then
+ let n := Z.add nx ny in
+ Qq n dx
+ else
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ Qq n d
+ end
+ end.
+
+ Definition add_norm x y :=
+ match x with
+ | Qz zx =>
+ match y with
+ | Qz zy => Qz (Z.add zx zy)
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ norm (Z.add (Z.mul zx (Z.Pos dy)) ny) dy
+ end
+ | Qq nx dx =>
+ if N.eq_bool dx N.zero then y
+ else match y with
+ | Qz zy => norm (Z.add nx (Z.mul zy (Z.Pos dx))) dx
+ | Qq ny dy =>
+ if N.eq_bool dy N.zero then x
+ else
+ if N.eq_bool dx dy then
+ let n := Z.add nx ny in
+ norm n dx
+ else
+ let n := Z.add (Z.mul nx (Z.Pos dy)) (Z.mul ny (Z.Pos dx)) in
+ let d := N.mul dx dy in
+ norm n d
+ end
+ end.
+
+ Definition sub x y := add x (opp y).
+
+ Definition sub_norm x y := add_norm x (opp y).
+
+ Definition mul x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => Qq (Z.mul zx ny) dy
+ | Qq nx dx, Qz zy => Qq (Z.mul nx zy) dx
+ | Qq nx dx, Qq ny dy => Qq (Z.mul nx ny) (N.mul dx dy)
+ end.
+
+ Definition mul_norm x y :=
+ match x, y with
+ | Qz zx, Qz zy => Qz (Z.mul zx zy)
+ | Qz zx, Qq ny dy => mul (Qz ny) (norm zx dy)
+ | Qq nx dx, Qz zy => mul (Qz nx) (norm zy dx)
+ | Qq nx dx, Qq ny dy => mul (norm nx dy) (norm ny dx)
+ end.
+
+ Definition inv x :=
+ match x with
+ | Qz (Z.Pos n) => Qq Z.one n
+ | Qz (Z.Neg n) => Qq Z.minus_one n
+ | Qq (Z.Pos n) d => Qq (Z.Pos d) n
+ | Qq (Z.Neg n) d => Qq (Z.Neg d) n
+ end.
+
+ Definition inv_norm x :=
+ match x with
+ | Qz (Z.Pos n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.one n
+ | Qz (Z.Neg n) =>
+ if N.eq_bool n N.zero then zero else Qq Z.minus_one n
+ | Qq (Z.Pos n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Pos d) n
+ | Qq (Z.Neg n) d =>
+ if N.eq_bool n N.zero then zero else Qq (Z.Neg d) n
+ end.
+
+ Definition square x :=
+ match x with
+ | Qz zx => Qz (Z.square zx)
+ | Qq nx dx => Qq (Z.square nx) (N.square dx)
+ end.
+
+ Definition power_pos x p :=
+ match x with
+ | Qz zx => Qz (Z.power_pos zx p)
+ | Qq nx dx => Qq (Z.power_pos nx p) (N.power_pos dx p)
+ end.
+
+End Qbi.
+
+
+
+
diff --git a/theories/Ints/num/ZMake.v b/theories/Ints/num/ZMake.v
new file mode 100644
index 0000000000..f79b5478bd
--- /dev/null
+++ b/theories/Ints/num/ZMake.v
@@ -0,0 +1,224 @@
+Require Import ZArith.
+
+Module Type NType.
+
+ Parameter t : Set.
+
+ Parameter zero : t.
+ Parameter one : t.
+
+ Parameter of_N : N -> t.
+ Parameter to_Z : t -> Z.
+
+ Parameter compare : t -> t -> comparison.
+ Parameter eq_bool : t -> t -> bool.
+
+ Parameter succ : t -> t.
+ Parameter add : t -> t -> t.
+ Parameter pred : t -> t.
+ Parameter sub : t -> t -> t.
+
+ Parameter mul : t -> t -> t.
+ Parameter square : t -> t.
+ Parameter power_pos : t -> positive -> t.
+ Parameter sqrt : t -> t.
+
+ Parameter div_eucl : t -> t -> t * t.
+ Parameter div : t -> t -> t.
+ Parameter modulo : t -> t -> t.
+ Parameter gcd : t -> t -> t.
+
+End NType.
+
+Module Make (N:NType).
+
+ Inductive t_ : Set :=
+ | Pos : N.t -> t_
+ | Neg : N.t -> t_.
+
+ Definition t := t_.
+
+ Definition zero := Pos N.zero.
+ Definition one := Pos N.one.
+ Definition minus_one := Neg N.one.
+
+ Definition of_Z x :=
+ match x with
+ | Zpos x => Pos (N.of_N (Npos x))
+ | Z0 => zero
+ | Zneg x => Neg (N.of_N (Npos x))
+ end.
+
+ Definition to_Z x :=
+ match x with
+ | Pos nx => N.to_Z nx
+ | Neg nx => Zopp (N.to_Z nx)
+ end.
+
+ Definition compare x y :=
+ match x, y with
+ | Pos nx, Pos ny => N.compare nx ny
+ | Pos nx, Neg ny =>
+ match N.compare nx N.zero with
+ | Gt => Gt
+ | _ => N.compare ny N.zero
+ end
+ | Neg nx, Pos ny =>
+ match N.compare N.zero nx with
+ | Lt => Lt
+ | _ => N.compare N.zero ny
+ end
+ | Neg nx, Neg ny => N.compare ny nx
+ end.
+
+ Definition eq_bool x y :=
+ match compare x y with
+ | Eq => true
+ | _ => false
+ end.
+
+ Definition cmp_sign x y :=
+ match x, y with
+ | Pos nx, Neg ny =>
+ if N.eq_bool ny N.zero then Eq else Gt
+ | Neg nx, Pos ny =>
+ if N.eq_bool nx N.zero then Eq else Lt
+ | _, _ => Eq
+ end.
+
+ Definition to_N x :=
+ match x with
+ | Pos nx => nx
+ | Neg nx => nx
+ end.
+
+ Definition abs x := Pos (to_N x).
+
+ Definition opp x :=
+ match x with
+ | Pos nx => Neg nx
+ | Neg nx => Pos nx
+ end.
+
+ Definition succ x :=
+ match x with
+ | Pos n => Pos (N.succ n)
+ | Neg n =>
+ match N.compare N.zero n with
+ | Lt => Neg (N.pred n)
+ | _ => one
+ end
+ end.
+
+ Definition add x y :=
+ match x, y with
+ | Pos nx, Pos ny => Pos (N.add nx ny)
+ | Pos nx, Neg ny =>
+ match N.compare nx ny with
+ | Gt => Pos (N.sub nx ny)
+ | Eq => zero
+ | Lt => Neg (N.sub ny nx)
+ end
+ | Neg nx, Pos ny =>
+ match N.compare nx ny with
+ | Gt => Neg (N.sub nx ny)
+ | Eq => zero
+ | Lt => Pos (N.sub ny nx)
+ end
+ | Neg nx, Neg ny => Neg (N.add nx ny)
+ end.
+
+ Definition pred x :=
+ match x with
+ | Pos nx =>
+ match N.compare N.zero nx with
+ | Lt => Pos (N.pred nx)
+ | _ => minus_one
+ end
+ | Neg nx => Neg (N.succ nx)
+ end.
+
+ Definition sub x y :=
+ match x, y with
+ | Pos nx, Pos ny =>
+ match N.compare nx ny with
+ | Gt => Pos (N.sub nx ny)
+ | Eq => zero
+ | Lt => Neg (N.sub ny nx)
+ end
+ | Pos nx, Neg ny => Pos (N.add nx ny)
+ | Neg nx, Pos ny => Neg (N.add nx ny)
+ | Neg nx, Neg ny =>
+ match N.compare nx ny with
+ | Gt => Neg (N.sub nx ny)
+ | Eq => zero
+ | Lt => Pos (N.sub ny nx)
+ end
+ end.
+
+ Definition mul x y :=
+ match x, y with
+ | Pos nx, Pos ny => Pos (N.mul nx ny)
+ | Pos nx, Neg ny => Neg (N.mul nx ny)
+ | Neg nx, Pos ny => Neg (N.mul nx ny)
+ | Neg nx, Neg ny => Pos (N.mul nx ny)
+ end.
+
+ Definition square x :=
+ match x with
+ | Pos nx => Pos (N.square nx)
+ | Neg nx => Pos (N.square nx)
+ end.
+
+ Definition power_pos x p :=
+ match x with
+ | Pos nx => Pos (N.power_pos nx p)
+ | Neg nx =>
+ match p with
+ | xH => x
+ | xO _ => Pos (N.power_pos nx p)
+ | xI _ => Neg (N.power_pos nx p)
+ end
+ end.
+
+ Definition sqrt x :=
+ match x with
+ | Pos nx => Pos (N.sqrt nx)
+ | Neg nx => Neg N.zero
+ end.
+
+ Definition div_eucl x y :=
+ match x, y with
+ | Pos nx, Pos ny =>
+ let (q, r) := N.div_eucl nx ny in
+ (Pos q, Pos r)
+ | Pos nx, Neg ny =>
+ let (q, r) := N.div_eucl nx ny in
+ (Neg q, Pos r)
+ | Neg nx, Pos ny =>
+ let (q, r) := N.div_eucl nx ny in
+ match N.compare N.zero r with
+ | Eq => (Neg q, zero)
+ | _ => (Neg (N.succ q), Pos (N.sub ny r))
+ end
+ | Neg nx, Neg ny =>
+ let (q, r) := N.div_eucl nx ny in
+ match N.compare N.zero r with
+ | Eq => (Pos q, zero)
+ | _ => (Pos (N.succ q), Pos (N.sub ny r))
+ end
+ end.
+
+ Definition div x y := fst (div_eucl x y).
+
+ Definition modulo x y := snd (div_eucl x y).
+
+ Definition gcd x y :=
+ match x, y with
+ | Pos nx, Pos ny => Pos (N.gcd nx ny)
+ | Pos nx, Neg ny => Pos (N.gcd nx ny)
+ | Neg nx, Pos ny => Pos (N.gcd nx ny)
+ | Neg nx, Neg ny => Pos (N.gcd nx ny)
+ end.
+
+End Make.
diff --git a/theories/Ints/num/Zn2Z.v b/theories/Ints/num/Zn2Z.v
new file mode 100644
index 0000000000..b5c6466584
--- /dev/null
+++ b/theories/Ints/num/Zn2Z.v
@@ -0,0 +1,735 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith.
+Require Import ZAux.
+Require Import ZDivModAux.
+Require Import Basic_type.
+Require Import GenBase.
+Require Import GenAdd.
+Require Import GenSub.
+Require Import GenMul.
+Require Import GenSqrt.
+Require Import GenLift.
+Require Import GenDivn1.
+Require Import GenDiv.
+Require Import ZnZ.
+
+Open Local Scope Z_scope.
+
+
+Section Zn2Z.
+
+ Variable w : Set.
+ Variable w_op : znz_op w.
+ Let w_digits := w_op.(znz_digits).
+
+ Variable more_than_one_digit: 1 < Zpos w_digits.
+
+ Let w_to_Z := w_op.(znz_to_Z).
+ Let w_of_pos := w_op.(znz_of_pos).
+ Let w_head0 := w_op.(znz_head0).
+
+ Let w_0 := w_op.(znz_0).
+ Let w_1 := w_op.(znz_1).
+ Let w_Bm1 := w_op.(znz_Bm1).
+
+ Let w_WW := w_op.(znz_WW).
+ Let w_W0 := w_op.(znz_W0).
+ Let w_0W := w_op.(znz_0W).
+
+ Let w_compare := w_op.(znz_compare).
+ Let w_eq0 := w_op.(znz_eq0).
+
+ Let w_opp_c := w_op.(znz_opp_c).
+ Let w_opp := w_op.(znz_opp).
+ Let w_opp_carry := w_op.(znz_opp_carry).
+
+ Let w_succ_c := w_op.(znz_succ_c).
+ Let w_add_c := w_op.(znz_add_c).
+ Let w_add_carry_c := w_op.(znz_add_carry_c).
+ Let w_succ := w_op.(znz_succ).
+ Let w_add := w_op.(znz_add).
+ Let w_add_carry := w_op.(znz_add_carry).
+
+ Let w_pred_c := w_op.(znz_pred_c).
+ Let w_sub_c := w_op.(znz_sub_c).
+ Let w_sub_carry_c := w_op.(znz_sub_carry_c).
+ Let w_pred := w_op.(znz_pred).
+ Let w_sub := w_op.(znz_sub).
+ Let w_sub_carry := w_op.(znz_sub_carry).
+
+
+ Let w_mul_c := w_op.(znz_mul_c).
+ Let w_mul := w_op.(znz_mul).
+ Let w_square_c := w_op.(znz_square_c).
+
+ Let w_div21 := w_op.(znz_div21).
+ Let w_div_gt := w_op.(znz_div_gt).
+ Let w_div := w_op.(znz_div).
+
+ Let w_mod_gt := w_op.(znz_mod_gt).
+ Let w_mod := w_op.(znz_mod).
+
+ Let w_gcd_gt := w_op.(znz_gcd_gt).
+ Let w_gcd := w_op.(znz_gcd).
+
+ Let w_add_mul_div := w_op.(znz_add_mul_div).
+
+ Let w_pos_mod := w_op.(znz_pos_mod).
+
+ Let w_is_even := w_op.(znz_is_even).
+ Let w_sqrt2 := w_op.(znz_sqrt2).
+ Let w_sqrt := w_op.(znz_sqrt).
+
+ Let _zn2z := zn2z w.
+
+ Let wB := base w_digits.
+
+ Let w_Bm2 := w_pred w_Bm1.
+
+ Let ww_1 := ww_1 w_0 w_1.
+ Let ww_Bm1 := ww_Bm1 w_Bm1.
+
+ Let _ww_digits := xO w_digits.
+
+ Let to_Z := zn2z_to_Z wB w_to_Z.
+
+ Let ww_of_pos p :=
+ match w_of_pos p with
+ | (N0, l) => (N0, WW w_0 l)
+ | (Npos ph,l) =>
+ let (n,h) := w_of_pos ph in (n, w_WW h l)
+ end.
+
+ Let head0 :=
+ Eval lazy beta delta [ww_head0] in
+ ww_head0 w_0 w_compare w_head0 w_digits _ww_digits.
+
+ Let ww_WW := Eval lazy beta delta [ww_WW] in (@ww_WW w).
+ Let ww_0W := Eval lazy beta delta [ww_0W] in (@ww_0W w).
+ Let ww_W0 := Eval lazy beta delta [ww_W0] in (@ww_W0 w).
+
+ (* ** Comparison ** *)
+ Let compare :=
+ Eval lazy beta delta[ww_compare] in ww_compare w_0 w_compare.
+
+ Let eq0 (x:zn2z w) :=
+ match x with
+ | W0 => true
+ | _ => false
+ end.
+
+ (* ** Opposites ** *)
+ Let opp_c :=
+ Eval lazy beta delta [ww_opp_c] in ww_opp_c w_0 w_opp_c w_opp_carry.
+
+ Let opp :=
+ Eval lazy beta delta [ww_opp] in ww_opp w_0 w_opp_c w_opp_carry w_opp.
+
+ Let opp_carry :=
+ Eval lazy beta delta [ww_opp_carry] in ww_opp_carry w_WW ww_Bm1 w_opp_carry.
+
+ (* ** Additions ** *)
+
+ Let succ_c :=
+ Eval lazy beta delta [ww_succ_c] in ww_succ_c w_0 ww_1 w_succ_c.
+
+ Let add_c :=
+ Eval lazy beta delta [ww_add_c] in ww_add_c w_WW w_add_c w_add_carry_c.
+
+ Let add_carry_c :=
+ Eval lazy beta iota delta [ww_add_carry_c ww_succ_c] in
+ ww_add_carry_c w_0 w_WW ww_1 w_succ_c w_add_c w_add_carry_c.
+
+ Let succ :=
+ Eval lazy beta delta [ww_succ] in ww_succ w_W0 ww_1 w_succ_c w_succ.
+
+ Let add :=
+ Eval lazy beta delta [ww_add] in ww_add w_add_c w_add w_add_carry.
+
+ Let add_carry :=
+ Eval lazy beta iota delta [ww_add_carry ww_succ] in
+ ww_add_carry w_W0 ww_1 w_succ_c w_add_carry_c w_succ w_add w_add_carry.
+
+ (* ** Subtractions ** *)
+
+ Let pred_c :=
+ Eval lazy beta delta [ww_pred_c] in ww_pred_c w_Bm1 w_WW ww_Bm1 w_pred_c.
+
+ Let sub_c :=
+ Eval lazy beta iota delta [ww_sub_c ww_opp_c] in
+ ww_sub_c w_0 w_WW w_opp_c w_opp_carry w_sub_c w_sub_carry_c.
+
+ Let sub_carry_c :=
+ Eval lazy beta iota delta [ww_sub_carry_c ww_pred_c ww_opp_carry] in
+ ww_sub_carry_c w_Bm1 w_WW ww_Bm1 w_opp_carry w_pred_c w_sub_c w_sub_carry_c.
+
+ Let pred :=
+ Eval lazy beta delta [ww_pred] in ww_pred w_Bm1 w_WW ww_Bm1 w_pred_c w_pred.
+
+ Let sub :=
+ Eval lazy beta iota delta [ww_sub ww_opp] in
+ ww_sub w_0 w_WW w_opp_c w_opp_carry w_sub_c w_opp w_sub w_sub_carry.
+
+ Let sub_carry :=
+ Eval lazy beta iota delta [ww_sub_carry ww_pred ww_opp_carry] in
+ ww_sub_carry w_Bm1 w_WW ww_Bm1 w_opp_carry w_pred_c w_sub_carry_c w_pred
+ w_sub w_sub_carry.
+
+
+ (* ** Multiplication ** *)
+
+ Let mul_c :=
+ Eval lazy beta iota delta [ww_mul_c gen_mul_c] in
+ ww_mul_c w_0 w_1 w_WW w_W0 w_mul_c add_c add add_carry.
+
+ Let karatsuba_c :=
+ Eval lazy beta iota delta [ww_karatsuba_c gen_mul_c kara_prod] in
+ ww_karatsuba_c w_0 w_1 w_WW w_W0 w_compare w_add w_sub w_mul_c
+ add_c add add_carry sub_c sub.
+
+ Let mul :=
+ Eval lazy beta delta [ww_mul] in
+ ww_mul w_W0 w_add w_mul_c w_mul add.
+
+ Let square_c :=
+ Eval lazy beta delta [ww_square_c] in
+ ww_square_c w_0 w_1 w_WW w_W0 w_mul_c w_square_c add_c add add_carry.
+
+ (* Division operation *)
+
+ Let div32 :=
+ Eval lazy beta iota delta [w_div32] in
+ w_div32 w_0 w_Bm1 w_Bm2 w_WW w_compare w_add_c w_add_carry_c
+ w_add w_add_carry w_pred w_sub w_mul_c w_div21 sub_c.
+
+ Let div21 :=
+ Eval lazy beta iota delta [ww_div21] in
+ ww_div21 w_0 w_0W div32 ww_1 compare sub.
+
+ Let add_mul_div :=
+ Eval lazy beta delta [ww_add_mul_div] in
+ ww_add_mul_div w_0 w_WW w_W0 w_0W w_add_mul_div w_digits.
+
+ Let div_gt :=
+ Eval lazy beta delta [ww_div_gt] in
+ ww_div_gt w_digits w_0 w_WW w_0W w_compare w_eq0 w_sub_c w_sub w_sub_carry
+ w_div_gt w_add_mul_div w_head0 w_div21 div32 _ww_digits ww_1 add_mul_div.
+
+ Let div :=
+ Eval lazy beta delta [ww_div] in ww_div ww_1 compare div_gt.
+
+ Let mod_gt :=
+ Eval lazy beta delta [ww_mod_gt] in
+ ww_mod_gt w_digits w_0 w_WW w_0W w_compare w_eq0 w_sub_c w_sub w_sub_carry
+ w_mod_gt w_add_mul_div w_head0 w_div21 div32 _ww_digits add_mul_div.
+
+ Let mod_ :=
+ Eval lazy beta delta [ww_mod] in ww_mod compare mod_gt.
+
+ Let pos_mod :=
+ Eval lazy beta delta [ww_pos_mod] in ww_pos_mod w_0 w_digits w_WW w_pos_mod.
+
+ Let is_even :=
+ Eval lazy beta delta [ww_is_even] in ww_is_even w_is_even.
+
+ Let sqrt2 :=
+ Eval lazy beta delta [ww_sqrt2] in
+ ww_sqrt2 w_is_even w_compare w_0 w_1 w_Bm1 w_sub w_square_c
+ w_div21 w_add_mul_div w_digits w_add_c w_sqrt2 pred_c
+ pred add_c add sub_c add_mul_div.
+
+ Let sqrt :=
+ Eval lazy beta delta [ww_sqrt] in
+ ww_sqrt w_0 w_add_mul_div w_digits w_sqrt2
+ add_mul_div head0 compare.
+
+ Let gcd_gt_fix :=
+ Eval cbv beta delta [ww_gcd_gt_aux ww_gcd_gt_body] in
+ ww_gcd_gt_aux w_digits w_0 w_WW w_compare w_sub_c w_sub w_sub_carry w_gcd_gt
+ w_add_mul_div w_head0 w_div21 div32 _ww_digits add_mul_div.
+
+ Let gcd_cont :=
+ Eval lazy beta delta [gcd_cont] in gcd_cont ww_1 w_1 w_compare.
+
+ Let gcd_gt :=
+ Eval lazy beta delta [ww_gcd_gt] in
+ ww_gcd_gt w_0 w_eq0 w_gcd_gt _ww_digits gcd_gt_fix gcd_cont.
+
+ Let gcd :=
+ Eval lazy beta delta [ww_gcd] in
+ ww_gcd compare w_0 w_eq0 w_gcd_gt _ww_digits gcd_gt_fix gcd_cont.
+
+ (* ** Record of operators on 2 words *)
+
+ Definition mk_zn2z_op :=
+ mk_znz_op _ww_digits
+ to_Z ww_of_pos head0
+ W0 ww_1 ww_Bm1
+ ww_WW ww_W0 ww_0W
+ compare eq0
+ opp_c opp opp_carry
+ succ_c add_c add_carry_c
+ succ add add_carry
+ pred_c sub_c sub_carry_c
+ pred sub sub_carry
+ mul_c mul square_c
+ div21 div_gt div
+ mod_gt mod_
+ gcd_gt gcd
+ add_mul_div
+ pos_mod
+ is_even
+ sqrt2
+ sqrt.
+
+ Definition mk_zn2z_op_karatsuba :=
+ mk_znz_op _ww_digits
+ to_Z ww_of_pos head0
+ W0 ww_1 ww_Bm1
+ ww_WW ww_W0 ww_0W
+ compare eq0
+ opp_c opp opp_carry
+ succ_c add_c add_carry_c
+ succ add add_carry
+ pred_c sub_c sub_carry_c
+ pred sub sub_carry
+ karatsuba_c mul square_c
+ div21 div_gt div
+ mod_gt mod_
+ gcd_gt gcd
+ add_mul_div
+ pos_mod
+ is_even
+ sqrt2
+ sqrt.
+
+ (* Proof *)
+ Variable op_spec : znz_spec w_op.
+
+ Hint Resolve
+ (spec_to_Z op_spec)
+ (spec_of_pos op_spec)
+ (spec_0 op_spec)
+ (spec_1 op_spec)
+ (spec_Bm1 op_spec)
+ (spec_WW op_spec)
+ (spec_0W op_spec)
+ (spec_W0 op_spec)
+ (spec_compare op_spec)
+ (spec_eq0 op_spec)
+ (spec_opp_c op_spec)
+ (spec_opp op_spec)
+ (spec_opp_carry op_spec)
+ (spec_succ_c op_spec)
+ (spec_add_c op_spec)
+ (spec_add_carry_c op_spec)
+ (spec_succ op_spec)
+ (spec_add op_spec)
+ (spec_add_carry op_spec)
+ (spec_pred_c op_spec)
+ (spec_sub_c op_spec)
+ (spec_sub_carry_c op_spec)
+ (spec_pred op_spec)
+ (spec_sub op_spec)
+ (spec_sub_carry op_spec)
+ (spec_mul_c op_spec)
+ (spec_mul op_spec)
+ (spec_square_c op_spec)
+ (spec_div21 op_spec)
+ (spec_div_gt op_spec)
+ (spec_div op_spec)
+ (spec_mod_gt op_spec)
+ (spec_mod op_spec)
+ (spec_gcd_gt op_spec)
+ (spec_gcd op_spec)
+ (spec_head0 op_spec)
+ (spec_add_mul_div op_spec)
+ (spec_pos_mod)
+ (spec_is_even)
+ (spec_sqrt2)
+ (spec_sqrt).
+
+ Let wwB := base _ww_digits.
+
+ Notation "[| x |]" := (to_Z x) (at level 0, x at level 99).
+
+ Notation "[+| c |]" :=
+ (interp_carry 1 wwB to_Z c) (at level 0, x at level 99).
+
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wwB to_Z c) (at level 0, x at level 99).
+
+ Notation "[[ x ]]" := (zn2z_to_Z wwB to_Z x) (at level 0, x at level 99).
+
+ Let spec_ww_to_Z : forall x, 0 <= [| x |] < wwB.
+ Proof. refine (spec_ww_to_Z w_digits w_to_Z _);auto. Qed.
+
+ Let spec_ww_of_pos : forall p,
+ Zpos p = (Z_of_N (fst (ww_of_pos p)))*wwB + [|(snd (ww_of_pos p))|].
+ Proof.
+ unfold ww_of_pos;intros.
+ assert (H:= spec_of_pos op_spec p);unfold w_of_pos;
+ destruct (znz_of_pos w_op p). simpl in H.
+ rewrite H;clear H;destruct n;simpl to_Z.
+ simpl;unfold w_to_Z,w_0;rewrite (spec_0 op_spec);trivial.
+ unfold Z_of_N; assert (H:= spec_of_pos op_spec p0);
+ destruct (znz_of_pos w_op p0). simpl in H.
+ rewrite H;unfold fst, snd,Z_of_N, w_WW, to_Z.
+ rewrite (spec_WW op_spec). replace wwB with (wB*wB).
+ unfold wB,w_digits;clear H;destruct n;ring.
+ symmetry. rewrite <- Zpower_2; exact (wwB_wBwB w_digits).
+ Qed.
+
+ Let spec_ww_0 : [|W0|] = 0.
+ Proof. reflexivity. Qed.
+
+ Let spec_ww_1 : [|ww_1|] = 1.
+ Proof. refine (spec_ww_1 w_0 w_1 w_digits w_to_Z _ _);auto. Qed.
+
+ Let spec_ww_Bm1 : [|ww_Bm1|] = wwB - 1.
+ Proof. refine (spec_ww_Bm1 w_Bm1 w_digits w_to_Z _);auto. Qed.
+
+ Let spec_ww_WW : forall h l, [[ww_WW h l]] = [|h|] * wwB + [|l|].
+ Proof.
+ intros h l. replace wwB with (wB*wB). destruct h;simpl.
+ destruct l;simpl;ring. ring.
+ symmetry. rewrite <- Zpower_2; exact (wwB_wBwB w_digits).
+ Qed.
+
+ Let spec_ww_0W : forall l, [[ww_0W l]] = [|l|].
+ Proof.
+ intros l. replace wwB with (wB*wB).
+ destruct l;simpl;ring.
+ symmetry. ring_simplify; exact (wwB_wBwB w_digits).
+ Qed.
+
+ Let spec_ww_W0 : forall h, [[ww_W0 h]] = [|h|]*wwB.
+ Proof.
+ intros h. replace wwB with (wB*wB).
+ destruct h;simpl;ring.
+ symmetry. ring_simplify; exact (wwB_wBwB w_digits).
+ Qed.
+
+ Let spec_ww_compare :
+ forall x y,
+ match compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end.
+ Proof.
+ refine (spec_ww_compare w_0 w_digits w_to_Z w_compare _ _ _);auto.
+ exact (spec_compare op_spec).
+ Qed.
+
+ Let spec_ww_eq0 : forall x, eq0 x = true -> [|x|] = 0.
+ Proof. destruct x;simpl;intros;trivial;discriminate. Qed.
+
+ Let spec_ww_opp_c : forall x, [-|opp_c x|] = -[|x|].
+ Proof.
+ refine(spec_ww_opp_c w_0 w_0 W0 w_opp_c w_opp_carry w_digits w_to_Z _ _ _ _);
+ auto.
+ Qed.
+
+ Let spec_ww_opp : forall x, [|opp x|] = (-[|x|]) mod wwB.
+ Proof.
+ refine(spec_ww_opp w_0 w_0 W0 w_opp_c w_opp_carry w_opp
+ w_digits w_to_Z _ _ _ _ _);
+ auto.
+ Qed.
+
+ Let spec_ww_opp_carry : forall x, [|opp_carry x|] = wwB - [|x|] - 1.
+ Proof.
+ refine (spec_ww_opp_carry w_WW ww_Bm1 w_opp_carry w_digits w_to_Z _ _ _);
+ auto. exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_succ_c : forall x, [+|succ_c x|] = [|x|] + 1.
+ Proof.
+ refine (spec_ww_succ_c w_0 w_0 ww_1 w_succ_c w_digits w_to_Z _ _ _ _);auto.
+ Qed.
+
+ Let spec_ww_add_c : forall x y, [+|add_c x y|] = [|x|] + [|y|].
+ Proof.
+ refine (spec_ww_add_c w_WW w_add_c w_add_carry_c w_digits w_to_Z _ _ _);auto.
+ exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_add_carry_c : forall x y, [+|add_carry_c x y|] = [|x|]+[|y|]+1.
+ Proof.
+ refine (spec_ww_add_carry_c w_0 w_0 w_WW ww_1 w_succ_c w_add_c w_add_carry_c
+ w_digits w_to_Z _ _ _ _ _ _ _);auto. exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_succ : forall x, [|succ x|] = ([|x|] + 1) mod wwB.
+ Proof.
+ refine (spec_ww_succ w_W0 ww_1 w_succ_c w_succ w_digits w_to_Z _ _ _ _ _);
+ auto. exact (spec_W0 op_spec).
+ Qed.
+
+ Let spec_ww_add : forall x y, [|add x y|] = ([|x|] + [|y|]) mod wwB.
+ Proof.
+ refine (spec_ww_add w_add_c w_add w_add_carry w_digits w_to_Z _ _ _ _);auto.
+ Qed.
+
+ Let spec_ww_add_carry : forall x y, [|add_carry x y|]=([|x|]+[|y|]+1)mod wwB.
+ Proof.
+ refine (spec_ww_add_carry w_W0 ww_1 w_succ_c w_add_carry_c w_succ
+ w_add w_add_carry w_digits w_to_Z _ _ _ _ _ _ _ _);auto.
+ exact (spec_W0 op_spec).
+ Qed.
+
+ Let spec_ww_pred_c : forall x, [-|pred_c x|] = [|x|] - 1.
+ Proof.
+ refine (spec_ww_pred_c w_0 w_Bm1 w_WW ww_Bm1 w_pred_c w_digits w_to_Z
+ _ _ _ _ _);auto. exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_sub_c : forall x y, [-|sub_c x y|] = [|x|] - [|y|].
+ Proof.
+ refine (spec_ww_sub_c w_0 w_0 w_WW W0 w_opp_c w_opp_carry w_sub_c
+ w_sub_carry_c w_digits w_to_Z _ _ _ _ _ _ _);auto. exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_sub_carry_c : forall x y, [-|sub_carry_c x y|] = [|x|]-[|y|]-1.
+ Proof.
+ refine (spec_ww_sub_carry_c w_0 w_Bm1 w_WW ww_Bm1 w_opp_carry w_pred_c
+ w_sub_c w_sub_carry_c w_digits w_to_Z _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_pred : forall x, [|pred x|] = ([|x|] - 1) mod wwB.
+ Proof.
+ refine (spec_ww_pred w_0 w_Bm1 w_WW ww_Bm1 w_pred_c w_pred w_digits w_to_Z
+ _ _ _ _ _ _);auto. exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_sub : forall x y, [|sub x y|] = ([|x|] - [|y|]) mod wwB.
+ Proof.
+ refine (spec_ww_sub w_0 w_0 w_WW W0 w_opp_c w_opp_carry w_sub_c w_opp
+ w_sub w_sub_carry w_digits w_to_Z _ _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_sub_carry : forall x y, [|sub_carry x y|]=([|x|]-[|y|]-1) mod wwB.
+ Proof.
+ refine (spec_ww_sub_carry w_0 w_Bm1 w_WW ww_Bm1 w_opp_carry w_pred_c
+ w_sub_carry_c w_pred w_sub w_sub_carry w_digits w_to_Z _ _ _ _ _ _ _ _ _ _);
+ auto. exact (spec_WW op_spec).
+ Qed.
+
+ Let spec_ww_mul_c : forall x y, [[mul_c x y ]] = [|x|] * [|y|].
+ Proof.
+ refine (spec_ww_mul_c w_0 w_1 w_WW w_W0 w_mul_c add_c add add_carry w_digits
+ w_to_Z _ _ _ _ _ _ _ _ _);auto. exact (spec_WW op_spec).
+ exact (spec_W0 op_spec). exact (spec_mul_c op_spec).
+ Qed.
+
+ Let spec_ww_karatsuba_c : forall x y, [[karatsuba_c x y ]] = [|x|] * [|y|].
+ Proof.
+ refine (spec_ww_karatsuba_c _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ _ _ _ _ _ _ _ _ _ _ _ _); auto.
+ exact (spec_WW op_spec).
+ exact (spec_W0 op_spec).
+ exact (spec_compare op_spec).
+ exact (spec_mul_c op_spec).
+ Qed.
+
+ Let spec_ww_mul : forall x y, [|mul x y|] = ([|x|] * [|y|]) mod wwB.
+ Proof.
+ refine (spec_ww_mul w_W0 w_add w_mul_c w_mul add w_digits w_to_Z _ _ _ _ _);
+ auto. exact (spec_W0 op_spec). exact (spec_mul_c op_spec).
+ Qed.
+
+ Let spec_ww_square_c : forall x, [[square_c x]] = [|x|] * [|x|].
+ Proof.
+ refine (spec_ww_square_c w_0 w_1 w_WW w_W0 w_mul_c w_square_c add_c add
+ add_carry w_digits w_to_Z _ _ _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec). exact (spec_W0 op_spec).
+ exact (spec_mul_c op_spec). exact (spec_square_c op_spec).
+ Qed.
+
+ Let spec_w_div32 : forall a1 a2 a3 b1 b2,
+ wB / 2 <= (w_to_Z b1) ->
+ [|WW a1 a2|] < [|WW b1 b2|] ->
+ let (q, r) := div32 a1 a2 a3 b1 b2 in
+ (w_to_Z a1) * wwB + (w_to_Z a2) * wB + (w_to_Z a3) =
+ (w_to_Z q) * ((w_to_Z b1)*wB + (w_to_Z b2)) + [|r|] /\
+ 0 <= [|r|] < (w_to_Z b1)*wB + w_to_Z b2.
+ Proof.
+ refine (spec_w_div32 w_0 w_Bm1 w_Bm2 w_WW w_compare w_add_c w_add_carry_c
+ w_add w_add_carry w_pred w_sub w_mul_c w_div21 sub_c w_digits w_to_Z
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);auto.
+ unfold w_Bm2, w_to_Z, w_pred, w_Bm1.
+ rewrite (spec_pred op_spec);rewrite (spec_Bm1 op_spec).
+ unfold w_digits;rewrite Zmod_def_small. ring.
+ assert (H:= wB_pos(znz_digits w_op)). omega.
+ exact (spec_WW op_spec). exact (spec_compare op_spec).
+ exact (spec_mul_c op_spec). exact (spec_div21 op_spec).
+ Qed.
+
+ Let spec_ww_div21 : forall a1 a2 b,
+ wwB/2 <= [|b|] ->
+ [|a1|] < [|b|] ->
+ let (q,r) := div21 a1 a2 b in
+ [|a1|] *wwB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+ Proof.
+ refine (spec_ww_div21 w_0 w_0W div32 ww_1 compare sub w_digits w_to_Z
+ _ _ _ _ _ _ _);auto. exact (spec_0W op_spec).
+ Qed.
+
+ Let spec_ww_head0 : forall x, 0 < [|x|] ->
+ wwB/ 2 <= 2 ^ (Z_of_N (head0 x)) * [|x|] < wwB.
+ Proof.
+ refine (spec_ww_head0 w_0 w_compare w_head0 w_digits _ww_digits
+ w_to_Z _ _ _ _);auto. exact (spec_compare op_spec).
+ Qed.
+
+ Lemma spec_ww_add_mul_div : forall x y p,
+ Zpos p < Zpos _ww_digits ->
+ [| add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos _ww_digits) - (Zpos p)))) mod wwB.
+ Proof.
+ refine (@spec_ww_add_mul_div w w_0 w_WW w_W0 w_0W w_add_mul_div w_digits
+ w_to_Z _ _ _ _ _ _);auto. exact (spec_WW op_spec).
+ exact (spec_W0 op_spec). exact (spec_0W op_spec).
+ Qed.
+
+ Let spec_ww_div_gt : forall a b,
+ [|a|] > [|b|] -> 0 < [|b|] ->
+ let (q,r) := div_gt a b in
+ [|a|] = [|q|] * [|b|] + [|r|] /\ 0 <= [|r|] < [|b|].
+ Proof.
+ refine (@spec_ww_div_gt w w_digits w_0 w_WW w_0W w_compare w_eq0
+ w_opp_c w_opp w_opp_carry w_sub_c w_sub w_sub_carry w_div_gt
+ w_add_mul_div w_head0 w_div21 div32 _ww_digits ww_1 add_mul_div w_to_Z
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec). exact (spec_0W op_spec).
+ exact (spec_compare op_spec). exact (spec_div_gt op_spec).
+ exact (spec_div21 op_spec). exact spec_ww_add_mul_div.
+ Qed.
+
+ Let spec_ww_div : forall a b, 0 < [|b|] ->
+ let (q,r) := div a b in
+ [|a|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|].
+ Proof.
+ refine (spec_ww_div w_digits ww_1 compare div_gt w_to_Z _ _ _ _);auto.
+ Qed.
+
+ Let spec_ww_mod_gt : forall a b,
+ [|a|] > [|b|] -> 0 < [|b|] ->
+ [|mod_gt a b|] = [|a|] mod [|b|].
+ Proof.
+ refine (@spec_ww_mod_gt w w_digits w_0 w_WW w_0W w_compare w_eq0
+ w_opp_c w_opp w_opp_carry w_sub_c w_sub w_sub_carry w_div_gt w_mod_gt
+ w_add_mul_div w_head0 w_div21 div32 _ww_digits ww_1 add_mul_div w_to_Z
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec). exact (spec_0W op_spec).
+ exact (spec_compare op_spec). exact (spec_div_gt op_spec).
+ exact (spec_div21 op_spec). exact spec_ww_add_mul_div.
+ Qed.
+
+ Let spec_ww_mod : forall a b, 0 < [|b|] -> [|mod_ a b|] = [|a|] mod [|b|].
+ Proof.
+ refine (spec_ww_mod w_digits W0 compare mod_gt w_to_Z _ _ _);auto.
+ Qed.
+
+ Let spec_ww_gcd_gt : forall a b, [|a|] > [|b|] ->
+ Zis_gcd [|a|] [|b|] [|gcd_gt a b|].
+ Proof.
+ refine (@spec_ww_gcd_gt w w_digits W0 w_to_Z _
+ w_0 w_0 w_eq0 w_gcd_gt _ww_digits
+ _ gcd_gt_fix _ _ _ _ gcd_cont _);auto.
+ refine (@spec_ww_gcd_gt_aux w w_digits w_0 w_WW w_compare w_opp_c w_opp
+ w_opp_carry w_sub_c w_sub w_sub_carry w_gcd_gt w_add_mul_div w_head0
+ w_div21 div32 _ww_digits ww_1 add_mul_div w_to_Z
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec). exact (spec_compare op_spec).
+ exact (spec_div21 op_spec). exact spec_ww_add_mul_div.
+ refine (@spec_gcd_cont w w_digits ww_1 w_to_Z _ _ w_0 w_1 w_compare
+ _ _);auto. exact (spec_compare op_spec).
+ Qed.
+
+ Let spec_ww_gcd : forall a b, Zis_gcd [|a|] [|b|] [|gcd a b|].
+ Proof.
+ refine (@spec_ww_gcd w w_digits W0 compare w_to_Z _ _ w_0 w_0 w_eq0 w_gcd_gt
+ _ww_digits _ gcd_gt_fix _ _ _ _ gcd_cont _);auto.
+ refine (@spec_ww_gcd_gt_aux w w_digits w_0 w_WW w_compare w_opp_c w_opp
+ w_opp_carry w_sub_c w_sub w_sub_carry w_gcd_gt w_add_mul_div w_head0
+ w_div21 div32 _ww_digits ww_1 add_mul_div w_to_Z
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);auto.
+ exact (spec_WW op_spec). exact (spec_compare op_spec).
+ exact (spec_div21 op_spec). exact spec_ww_add_mul_div.
+ refine (@spec_gcd_cont w w_digits ww_1 w_to_Z _ _ w_0 w_1 w_compare
+ _ _);auto. exact (spec_compare op_spec).
+ Qed.
+
+ Let spec_ww_is_even : forall x,
+ match is_even x with
+ true => [|x|] mod 2 = 0
+ | false => [|x|] mod 2 = 1
+ end.
+ Proof.
+ refine (@spec_ww_is_even w w_is_even w_0 w_1 w_Bm1 w_digits _ _ _); auto.
+ exact (spec_is_even op_spec).
+ Qed.
+
+ Let spec_ww_sqrt2 : forall x y,
+ wwB/ 4 <= [|x|] ->
+ let (s,r) := sqrt2 x y in
+ [[WW x y]] = [|s|] ^ 2 + [+|r|] /\
+ [+|r|] <= 2 * [|s|].
+ Proof.
+ intros x y H.
+ refine (@spec_ww_sqrt2 w w_is_even w_compare w_0 w_1 w_Bm1
+ w_sub w_square_c w_div21 w_add_mul_div w_digits
+ w_add_c w_sqrt2 pred_c pred add_c add sub_c add_mul_div
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _); auto.
+ exact (spec_is_even op_spec).
+ exact (spec_compare op_spec).
+ exact (spec_square_c op_spec).
+ exact (spec_div21 op_spec).
+ exact (spec_ww_add_mul_div).
+ exact (spec_sqrt2 op_spec).
+ Qed.
+
+ Let spec_ww_sqrt : forall x,
+ [|sqrt x|] ^ 2 <= [|x|] < ([|sqrt x|] + 1) ^ 2.
+ Proof.
+ refine (@spec_ww_sqrt w w_0 w_1 w_Bm1 w_add_mul_div w_digits
+ w_sqrt2 add_mul_div head0 compare
+ _ _ _ _ _ _ _ _ _ _); auto.
+ exact (spec_ww_add_mul_div).
+ exact (spec_sqrt2 op_spec).
+ Qed.
+
+ Lemma mk_znz2_spec : znz_spec mk_zn2z_op.
+ Proof.
+ apply mk_znz_spec;auto.
+ exact spec_ww_add_mul_div.
+ refine (@spec_ww_pos_mod w w_0 w_digits w_WW w_pos_mod w_to_Z
+ _ _ _ _);auto. exact (spec_WW op_spec). exact (spec_pos_mod op_spec).
+ Qed.
+
+ Lemma mk_znz2_karatsuba_spec : znz_spec mk_zn2z_op_karatsuba.
+ Proof.
+ apply mk_znz_spec;auto.
+ exact spec_ww_add_mul_div.
+ refine (@spec_ww_pos_mod w w_0 w_digits w_WW w_pos_mod w_to_Z
+ _ _ _ _);auto. exact (spec_WW op_spec). exact (spec_pos_mod op_spec).
+ Qed.
+
+End Zn2Z.
+
diff --git a/theories/Ints/num/ZnZ.v b/theories/Ints/num/ZnZ.v
new file mode 100644
index 0000000000..5efcad2d0f
--- /dev/null
+++ b/theories/Ints/num/ZnZ.v
@@ -0,0 +1,300 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import Tactic.
+Require Import ZArith.
+Require Import Znumtheory.
+Require Import Basic_type.
+Require Import GenBase.
+
+Open Local Scope Z_scope.
+
+Section ZnZ_Op.
+
+ Variable znz : Set.
+
+ Record znz_op : Set := mk_znz_op {
+ (* Conversion functions with Z *)
+ znz_digits : positive;
+ znz_to_Z : znz -> Z;
+ znz_of_pos : positive -> N * znz;
+ znz_head0 : znz -> N;
+ (* Basic constructors *)
+ znz_0 : znz;
+ znz_1 : znz;
+ znz_Bm1 : znz;
+ znz_WW : znz -> znz -> zn2z znz;
+ znz_W0 : znz -> zn2z znz;
+ znz_0W : znz -> zn2z znz;
+
+ (* Comparison *)
+ znz_compare : znz -> znz -> comparison;
+ znz_eq0 : znz -> bool;
+
+ (* Basic arithmetic operations *)
+ znz_opp_c : znz -> carry znz;
+ znz_opp : znz -> znz;
+ znz_opp_carry : znz -> znz; (* the carry is know to be -1 *)
+
+ znz_succ_c : znz -> carry znz;
+ znz_add_c : znz -> znz -> carry znz;
+ znz_add_carry_c : znz -> znz -> carry znz;
+ znz_succ : znz -> znz;
+ znz_add : znz -> znz -> znz;
+ znz_add_carry : znz -> znz -> znz;
+
+ znz_pred_c : znz -> carry znz;
+ znz_sub_c : znz -> znz -> carry znz;
+ znz_sub_carry_c : znz -> znz -> carry znz;
+ znz_pred : znz -> znz;
+ znz_sub : znz -> znz -> znz;
+ znz_sub_carry : znz -> znz -> znz;
+
+ znz_mul_c : znz -> znz -> zn2z znz;
+ znz_mul : znz -> znz -> znz;
+ znz_square_c : znz -> zn2z znz;
+
+ (* Special divisions operations *)
+ znz_div21 : znz -> znz -> znz -> znz*znz;
+ znz_div_gt : znz -> znz -> znz * znz;
+ znz_div : znz -> znz -> znz * znz;
+
+ znz_mod_gt : znz -> znz -> znz;
+ znz_mod : znz -> znz -> znz;
+
+ znz_gcd_gt : znz -> znz -> znz;
+ znz_gcd : znz -> znz -> znz;
+ znz_add_mul_div : positive -> znz -> znz -> znz;
+ znz_pos_mod : positive -> znz -> znz;
+
+ (* square root *)
+ znz_is_even : znz -> bool;
+ znz_sqrt2 : znz -> znz -> znz * carry znz;
+ znz_sqrt : znz -> znz }.
+
+End ZnZ_Op.
+
+Section Spec.
+ Variable w : Set.
+ Variable w_op : znz_op w.
+
+ Let w_digits := w_op.(znz_digits).
+ Let w_to_Z := w_op.(znz_to_Z).
+ Let w_of_pos := w_op.(znz_of_pos).
+ Let w_head0 := w_op.(znz_head0).
+
+ Let w0 := w_op.(znz_0).
+ Let w1 := w_op.(znz_1).
+ Let wBm1 := w_op.(znz_Bm1).
+
+ Let wWW := w_op.(znz_WW).
+ Let w0W := w_op.(znz_0W).
+ Let wW0 := w_op.(znz_W0).
+
+ Let w_compare := w_op.(znz_compare).
+ Let w_eq0 := w_op.(znz_eq0).
+
+ Let w_opp_c := w_op.(znz_opp_c).
+ Let w_opp := w_op.(znz_opp).
+ Let w_opp_carry := w_op.(znz_opp_carry).
+
+ Let w_succ_c := w_op.(znz_succ_c).
+ Let w_add_c := w_op.(znz_add_c).
+ Let w_add_carry_c := w_op.(znz_add_carry_c).
+ Let w_succ := w_op.(znz_succ).
+ Let w_add := w_op.(znz_add).
+ Let w_add_carry := w_op.(znz_add_carry).
+
+ Let w_pred_c := w_op.(znz_pred_c).
+ Let w_sub_c := w_op.(znz_sub_c).
+ Let w_sub_carry_c := w_op.(znz_sub_carry_c).
+ Let w_pred := w_op.(znz_pred).
+ Let w_sub := w_op.(znz_sub).
+ Let w_sub_carry := w_op.(znz_sub_carry).
+
+ Let w_mul_c := w_op.(znz_mul_c).
+ Let w_mul := w_op.(znz_mul).
+ Let w_square_c := w_op.(znz_square_c).
+
+ Let w_div21 := w_op.(znz_div21).
+ Let w_div_gt := w_op.(znz_div_gt).
+ Let w_div := w_op.(znz_div).
+
+ Let w_mod_gt := w_op.(znz_mod_gt).
+ Let w_mod := w_op.(znz_mod).
+
+ Let w_gcd_gt := w_op.(znz_gcd_gt).
+ Let w_gcd := w_op.(znz_gcd).
+
+ Let w_add_mul_div := w_op.(znz_add_mul_div).
+
+ Let w_pos_mod := w_op.(znz_pos_mod).
+
+ Let w_is_even := w_op.(znz_is_even).
+ Let w_sqrt2 := w_op.(znz_sqrt2).
+ Let w_sqrt := w_op.(znz_sqrt).
+
+ Notation "[| x |]" := (w_to_Z x) (at level 0, x at level 99).
+
+ Let wB := base w_digits.
+
+ Notation "[+| c |]" :=
+ (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[-| c |]" :=
+ (interp_carry (-1) wB w_to_Z c) (at level 0, x at level 99).
+
+ Notation "[|| x ||]" :=
+ (zn2z_to_Z wB w_to_Z x) (at level 0, x at level 99).
+
+ Notation "[! n | x !]" := (gen_to_Z w_digits w_to_Z n x)
+ (at level 0, x at level 99).
+
+ Record znz_spec : Set := mk_znz_spec {
+
+ (* Conversion functions with Z *)
+ spec_to_Z : forall x, 0 <= [| x |] < wB;
+ spec_of_pos : forall p,
+ Zpos p = (Z_of_N (fst (w_of_pos p)))*wB + [|(snd (w_of_pos p))|];
+
+ (* Basic constructors *)
+ spec_0 : [|w0|] = 0;
+ spec_1 : [|w1|] = 1;
+ spec_Bm1 : [|wBm1|] = wB - 1;
+ spec_WW : forall h l, [||wWW h l||] = [|h|] * wB + [|l|];
+ spec_0W : forall l, [||w0W l||] = [|l|];
+ spec_W0 : forall h, [||wW0 h||] = [|h|]*wB;
+
+ (* Comparison *)
+ spec_compare :
+ forall x y,
+ match w_compare x y with
+ | Eq => [|x|] = [|y|]
+ | Lt => [|x|] < [|y|]
+ | Gt => [|x|] > [|y|]
+ end;
+ spec_eq0 : forall x, w_eq0 x = true -> [|x|] = 0;
+ (* Basic arithmetic operations *)
+ spec_opp_c : forall x, [-|w_opp_c x|] = -[|x|];
+ spec_opp : forall x, [|w_opp x|] = (-[|x|]) mod wB;
+ spec_opp_carry : forall x, [|w_opp_carry x|] = wB - [|x|] - 1;
+
+ spec_succ_c : forall x, [+|w_succ_c x|] = [|x|] + 1;
+ spec_add_c : forall x y, [+|w_add_c x y|] = [|x|] + [|y|];
+ spec_add_carry_c : forall x y, [+|w_add_carry_c x y|] = [|x|] + [|y|] + 1;
+ spec_succ : forall x, [|w_succ x|] = ([|x|] + 1) mod wB;
+ spec_add : forall x y, [|w_add x y|] = ([|x|] + [|y|]) mod wB;
+ spec_add_carry :
+ forall x y, [|w_add_carry x y|] = ([|x|] + [|y|] + 1) mod wB;
+
+ spec_pred_c : forall x, [-|w_pred_c x|] = [|x|] - 1;
+ spec_sub_c : forall x y, [-|w_sub_c x y|] = [|x|] - [|y|];
+ spec_sub_carry_c : forall x y, [-|w_sub_carry_c x y|] = [|x|] - [|y|] - 1;
+ spec_pred : forall x, [|w_pred x|] = ([|x|] - 1) mod wB;
+ spec_sub : forall x y, [|w_sub x y|] = ([|x|] - [|y|]) mod wB;
+ spec_sub_carry :
+ forall x y, [|w_sub_carry x y|] = ([|x|] - [|y|] - 1) mod wB;
+
+ spec_mul_c : forall x y, [|| w_mul_c x y ||] = [|x|] * [|y|];
+ spec_mul : forall x y, [|w_mul x y|] = ([|x|] * [|y|]) mod wB;
+ spec_square_c : forall x, [|| w_square_c x||] = [|x|] * [|x|];
+
+ (* Special divisions operations *)
+ spec_div21 : forall a1 a2 b,
+ wB/2 <= [|b|] ->
+ [|a1|] < [|b|] ->
+ let (q,r) := w_div21 a1 a2 b in
+ [|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|];
+ spec_div_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
+ let (q,r) := w_div_gt a b in
+ [|a|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|];
+ spec_div : forall a b, 0 < [|b|] ->
+ let (q,r) := w_div a b in
+ [|a|] = [|q|] * [|b|] + [|r|] /\
+ 0 <= [|r|] < [|b|];
+
+ spec_mod_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
+ [|w_mod_gt a b|] = [|a|] mod [|b|];
+ spec_mod : forall a b, 0 < [|b|] ->
+ [|w_mod a b|] = [|a|] mod [|b|];
+
+ spec_gcd_gt : forall a b, [|a|] > [|b|] ->
+ Zis_gcd [|a|] [|b|] [|w_gcd_gt a b|];
+ spec_gcd : forall a b, Zis_gcd [|a|] [|b|] [|w_gcd a b|];
+
+
+ (* shift operations *)
+ spec_head0 : forall x, 0 < [|x|] ->
+ wB/ 2 <= 2 ^ (Z_of_N (w_head0 x)) * [|x|] < wB;
+ spec_add_mul_div : forall x y p,
+ Zpos p < Zpos w_digits ->
+ [| w_add_mul_div p x y |] =
+ ([|x|] * (Zpower 2 (Zpos p)) +
+ [|y|] / (Zpower 2 ((Zpos w_digits) - (Zpos p)))) mod wB;
+ spec_pos_mod : forall w p,
+ [|w_pos_mod p w|] = [|w|] mod (2 ^ Zpos p);
+ (* sqrt *)
+ spec_is_even : forall x,
+ if w_is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1;
+ spec_sqrt2 : forall x y,
+ wB/ 4 <= [|x|] ->
+ let (s,r) := w_sqrt2 x y in
+ [||WW x y||] = [|s|] ^ 2 + [+|r|] /\
+ [+|r|] <= 2 * [|s|];
+ spec_sqrt : forall x,
+ [|w_sqrt x|] ^ 2 <= [|x|] < ([|w_sqrt x|] + 1) ^ 2
+ }.
+
+End Spec.
+
+
+Section znz_of_pos.
+
+ Variable w : Set.
+ Variable w_op : znz_op w.
+ Variable op_spec : znz_spec w_op.
+
+ Notation "[| x |]" := (znz_to_Z w_op x) (at level 0, x at level 99).
+
+ Definition znz_of_Z (w:Set) (op:znz_op w) z :=
+ match z with
+ | Zpos p => snd (op.(znz_of_pos) p)
+ | _ => op.(znz_0)
+ end.
+
+ Theorem znz_of_pos_correct:
+ forall p, Zpos p < base (znz_digits w_op) -> [|(snd (znz_of_pos w_op p))|] = Zpos p.
+ intros p Hp.
+ generalize (spec_of_pos op_spec p).
+ case (znz_of_pos w_op p); intros n w1; simpl.
+ case n; simpl Npos; auto with zarith.
+ intros p1 Hp1; contradict Hp; apply Zle_not_lt.
+ rewrite Hp1; auto with zarith.
+ match goal with |- _ <= ?X + ?Y =>
+ apply Zle_trans with X; auto with zarith
+ end.
+ match goal with |- ?X <= _ =>
+ pattern X at 1; rewrite <- (Zmult_1_l);
+ apply Zmult_le_compat_r; auto with zarith
+ end.
+ case p1; simpl; intros; red; simpl; intros; discriminate.
+ unfold base; auto with zarith.
+ case (spec_to_Z op_spec w1); auto with zarith.
+ Qed.
+
+ Theorem znz_of_Z_correct:
+ forall p, 0 <= p < base (znz_digits w_op) -> [|znz_of_Z w_op p|] = p.
+ intros p; case p; simpl; try rewrite spec_0; auto.
+ intros; rewrite znz_of_pos_correct; auto with zarith.
+ intros p1 (H1, _); contradict H1; apply Zlt_not_le; red; simpl; auto.
+ Qed.
+End znz_of_pos.
diff --git a/theories/Ints/num/genN.ml b/theories/Ints/num/genN.ml
new file mode 100644
index 0000000000..bf6bf65353
--- /dev/null
+++ b/theories/Ints/num/genN.ml
@@ -0,0 +1,816 @@
+open Format
+
+let size = 3
+let sizeaux = 1
+
+let t = "t"
+let c = "N"
+
+(******* Start Printing ********)
+let basename = "N"
+
+
+let print_header fmt l =
+ let l = "ZArith"::"Basic_type"::"ZnZ"::"Zn2Z"::"Nbasic"::"GenMul"::
+ "GenDivn1"::"Lucas"::l in
+ List.iter (fun s -> fprintf fmt "Require Import %s.\n" s) l;
+ fprintf fmt "\n"
+
+let start_file post l =
+ let outname = basename^post^".v" in
+ let fd =
+ try
+ Unix.openfile outname [Unix.O_WRONLY;Unix.O_CREAT;Unix.O_TRUNC] 0o640
+ with _ ->
+ print_string ("can not open file "^outname^"\n");
+ exit 1 in
+ let out = Unix.out_channel_of_descr fd in
+ set_binary_mode_out out false;
+ let fmt = formatter_of_out_channel out in
+ print_header fmt l;
+ fmt
+
+
+
+(****** Print types *******)
+
+let print_Make () =
+ let fmt = start_file "Make" [] in
+
+ fprintf fmt "Module Type W0Type.\n";
+ fprintf fmt " Parameter w : Set.\n";
+ fprintf fmt " Parameter w_op : znz_op w.\n";
+ fprintf fmt " Parameter w_spec : znz_spec w_op.\n";
+ fprintf fmt "End W0Type.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt "Module Make (W0:W0Type).\n";
+ fprintf fmt " Import W0.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition w0 := W0.w.\n";
+ for i = 1 to size do
+ fprintf fmt " Definition w%i := zn2z w%i.\n" i (i-1)
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition w0_op := W0.w_op.\n";
+ for i = 1 to 3 do
+ fprintf fmt " Definition w%i_op := mk_zn2z_op w%i_op.\n" i (i-1)
+ done;
+ for i = 4 to size + 3 do
+ fprintf fmt " Definition w%i_op := mk_zn2z_op_karatsuba w%i_op.\n" i (i-1)
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Section Make_op.\n";
+ fprintf fmt " Variable mk : forall w', znz_op w' -> znz_op (zn2z w').\n";
+ fprintf fmt "\n";
+ fprintf fmt
+ " Fixpoint make_op_aux (n:nat) : znz_op (word w%i (S n)):=\n" size;
+ fprintf fmt " match n return znz_op (word w%i (S n)) with\n" size;
+ fprintf fmt " | O => w%i_op\n" (size+1);
+ fprintf fmt " | S n1 =>\n";
+ fprintf fmt " match n1 return znz_op (word w%i (S (S n1))) with\n" size;
+ fprintf fmt " | O => w%i_op\n" (size+2);
+ fprintf fmt " | S n2 =>\n";
+ fprintf fmt " match n2 return znz_op (word w%i (S (S (S n2)))) with\n"
+ size;
+ fprintf fmt " | O => w%i_op\n" (size+3);
+ fprintf fmt " | S n3 => mk _ (mk _ (mk _ (make_op_aux n3)))\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+ fprintf fmt " End Make_op.\n";
+ fprintf fmt "\n";
+ fprintf fmt " Definition make_op := make_op_aux mk_zn2z_op_karatsuba.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Inductive %s_ : Set :=\n" t;
+ for i = 0 to size do
+ fprintf fmt " | %s%i : w%i -> %s_\n" c i i t
+ done;
+ fprintf fmt " | %sn : forall n, word w%i (S n) -> %s_.\n" c size t;
+ fprintf fmt "\n";
+ fprintf fmt " Definition %s := %s_.\n" t t;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition w_0 := w0_op.(znz_0).\n";
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition one%i := w%i_op.(znz_1).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition zero := %s0 w_0.\n" c;
+ fprintf fmt " Definition one := %s0 one0.\n" c;
+ fprintf fmt "\n";
+
+ (* Successor function *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_succ_c := w%i_op.(znz_succ_c).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_succ := w%i_op.(znz_succ).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition succ x :=\n";
+ fprintf fmt " match x with\n";
+ for i = 0 to size-1 do
+ fprintf fmt " | %s%i wx =>\n" c i;
+ fprintf fmt " match w%i_succ_c wx with\n" i;
+ fprintf fmt " | C0 r => %s%i r\n" c i;
+ fprintf fmt " | C1 r => %s%i (WW one%i r)\n" c (i+1) i;
+ fprintf fmt " end\n";
+ done;
+ fprintf fmt " | %s%i wx =>\n" c size;
+ fprintf fmt " match w%i_succ_c wx with\n" size;
+ fprintf fmt " | C0 r => %s%i r\n" c size;
+ fprintf fmt " | C1 r => %sn 0 (WW one%i r)\n" c size ;
+ fprintf fmt " end\n";
+ fprintf fmt " | %sn n wx =>\n" c;
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " match op.(znz_succ_c) wx with\n";
+ fprintf fmt " | C0 r => %sn n r\n" c;
+ fprintf fmt " | C1 r => %sn (S n) (WW op.(znz_1) r)\n" c;
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ for i = 1 to size do
+ fprintf fmt " Definition extend%i :=\n" i;
+ fprintf fmt " Eval lazy beta zeta iota delta [extend]in extend %i.\n" i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_eq0 := w%i_op.(znz_eq0).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_0W := w%i_op.(znz_0W).\n" i i
+ done;
+ fprintf fmt "\n";
+ fprintf fmt " Definition w0_WW := w0_op.(znz_WW).\n";
+ fprintf fmt "\n";
+
+ (* Addition *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_add_c := w%i_op.(znz_add_c).\n" i i
+ done;
+ fprintf fmt "\n";
+(*
+ fprintf fmt " Definition add_c_1_0 x y :=\n";
+ fprintf fmt " match x with\n";
+ fprintf fmt " | W0 => C0 (w0_0W y)\n";
+ fprintf fmt " | WW xh xl =>
+ fprintf fmt " match w1_add_c xl y with\n";
+ fprintf fmt " | C0 rl => C0 (WW xh rl)\n";
+ fprintf fmt " | C1 rl =>\n";
+ fprintf fmt " match w1_succ_c xh with\n";
+ fprintf fmt " | C0 rh => C0 (WW rh rl)\n";
+ fprintf fmt " | C1 rh => C1 (w0_WW rh rl)\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ for i = 1 to size do
+ fprintf fmt " Definition add_c_n_%i :=\n" i;
+ fprintf fmt " add_c_smn1 w%i
+*)
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_add x y :=\n" i;
+ fprintf fmt " match w%i_add_c x y with\n" i;
+ fprintf fmt " | C0 r => %s%i r\n" c i;
+ fprintf fmt " | C1 r => ";
+ if i < size then fprintf fmt "%s%i (WW one%i r)\n" c (i+1) i
+ else fprintf fmt "%sn 0 (WW one%i r)\n" c size;
+ fprintf fmt " end.\n"
+ done;
+ fprintf fmt " Definition addn n (x y : word w%i (S n)) :=\n" size;
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " match op.(znz_add_c) x y with\n";
+ fprintf fmt " | C0 r => %sn n r\n" c;
+ fprintf fmt " | C1 r => %sn (S n) (WW op.(znz_1) r)" c;
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition add x y :=\n";
+ fprintf fmt " match x, y with\n";
+ fprintf fmt " | %s0 wx, %s0 wy => w0_add wx wy \n" c c;
+ for j = 1 to size do
+ fprintf fmt " | %s0 wx, %s%i wy =>\n" c c j;
+ fprintf fmt " if w0_eq0 wx then y else w%i_add " j;
+ if j = 1 then fprintf fmt "(WW w_0 wx) wy\n"
+ else fprintf fmt "(extend%i w0 (WW w_0 wx)) wy\n" (j-1)
+ done;
+ fprintf fmt " | %s0 wx, %sn n wy =>\n" c c;
+ fprintf fmt " if w0_eq0 wx then y\n";
+ fprintf fmt " else addn n (extend n w%i (extend%i w0 (WW w_0 wx))) wy\n"
+ size size;
+ for i = 1 to size do
+ fprintf fmt " | %s%i wx, %s0 wy =>\n" c i c;
+ fprintf fmt
+ " if w0_eq0 wy then x else w%i_add wx " i;
+ if i = 1 then fprintf fmt "(WW w_0 wy)\n"
+ else fprintf fmt "(extend%i w0 (WW w_0 wy))\n" (i-1);
+ for j = 1 to size do
+ fprintf fmt " | %s%i wx, %s%i wy => " c i c j;
+ if i < j then fprintf fmt "w%i_add (extend%i w%i wx) wy\n" j (j-i) (i-1)
+ else if i = j then fprintf fmt "w%i_add wx wy\n" j
+ else fprintf fmt "w%i_add wx (extend%i w%i wy)\n" i (i-j) (j-1)
+ done;
+ fprintf fmt
+ " | %s%i wx, %sn n wy => addn n (extend n w%i (extend%i w%i wx)) wy\n"
+ c i c size (size-i+1) (i-1)
+ done;
+ fprintf fmt " | %sn n wx, %s0 wy =>\n" c c;
+ fprintf fmt " if w0_eq0 wy then x\n";
+ fprintf fmt " else addn n wx (extend n w%i (extend%i w0 (WW w_0 wy)))\n"
+ size size;
+ for j = 1 to size do
+ fprintf fmt
+ " | %sn n wx, %s%i wy => addn n wx (extend n w%i (extend%i w%i wy))\n"
+ c c j size (size-j+1) (j-1);
+ done;
+ fprintf fmt " | %sn n wx, %sn m wy =>\n" c c;
+ fprintf fmt " match extend_to_max w%i n m wx wy with\n" size;
+ fprintf fmt " | inl wx' => addn m wx' wy\n";
+ fprintf fmt " | inr wy' => addn n wx wy'\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition reduce_0 (x:w) := %s0 x.\n" c;
+ fprintf fmt " Definition reduce_1 :=\n";
+ fprintf fmt " Eval lazy beta iota delta[reduce_n1] in\n";
+ fprintf fmt " reduce_n1 _ _ zero w0_eq0 %s0 %s1.\n" c c;
+ for i = 2 to size do
+ fprintf fmt " Definition reduce_%i :=\n" i;
+ fprintf fmt " Eval lazy beta iota delta[reduce_n1] in\n";
+ fprintf fmt " reduce_n1 _ _ zero w%i_eq0 reduce_%i %s%i.\n"
+ (i-1) (i-1) c i
+ done;
+ fprintf fmt " Definition reduce_%i :=\n" (size+1);
+ fprintf fmt " Eval lazy beta iota delta[reduce_n1] in\n";
+ fprintf fmt " reduce_n1 _ _ zero w%i_eq0 reduce_%i (%sn 0).\n"
+ size size c;
+
+ fprintf fmt " Definition reduce_n n := \n";
+ fprintf fmt " Eval lazy beta iota delta[reduce_n] in\n";
+ fprintf fmt " reduce_n _ _ zero reduce_%i %sn n.\n" (size + 1) c;
+ fprintf fmt "\n";
+
+ (* Predecessor *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_pred_c := w%i_op.(znz_pred_c).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition pred x :=\n";
+ fprintf fmt " match x with\n";
+ for i = 0 to size do
+ fprintf fmt " | %s%i wx =>\n" c i;
+ fprintf fmt " match w%i_pred_c wx with\n" i;
+ fprintf fmt " | C0 r => reduce_%i r\n" i;
+ fprintf fmt " | C1 r => zero\n";
+ fprintf fmt " end\n";
+ done;
+ fprintf fmt " | %sn n wx =>\n" c;
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " match op.(znz_pred_c) wx with\n";
+ fprintf fmt " | C0 r => reduce_n n r\n";
+ fprintf fmt " | C1 r => zero\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ (* Substraction *)
+ fprintf fmt "\n";
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_sub_c := w%i_op.(znz_sub_c).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_sub x y :=\n" i;
+ fprintf fmt " match w%i_sub_c x y with\n" i;
+ fprintf fmt " | C0 r => reduce_%i r\n" i;
+ fprintf fmt " | C1 r => zero\n";
+ fprintf fmt " end.\n"
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition subn n (x y : word w%i (S n)) :=\n" size;
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " match op.(znz_sub_c) x y with\n";
+ fprintf fmt " | C0 r => %sn n r\n" c;
+ fprintf fmt " | C1 r => %sn (S n) (WW op.(znz_1) r)" c;
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition sub x y :=\n";
+ fprintf fmt " match x, y with\n";
+ fprintf fmt " | %s0 wx, %s0 wy => w0_sub wx wy \n" c c;
+ for j = 1 to size do
+ fprintf fmt " | %s0 wx, %s%i wy =>\n" c c j;
+ fprintf fmt " if w0_eq0 wx then zero else w%i_sub " j;
+ if j = 1 then fprintf fmt "(WW w_0 wx) wy\n"
+ else fprintf fmt "(extend%i w0 (WW w_0 wx)) wy\n" (j-1)
+ done;
+ fprintf fmt " | %s0 wx, %sn n wy =>\n" c c;
+ fprintf fmt " if w0_eq0 wx then zero\n";
+ fprintf fmt " else subn n (extend n w%i (extend%i w0 (WW w_0 wx))) wy\n"
+ size size;
+ for i = 1 to size do
+ fprintf fmt " | %s%i wx, %s0 wy =>" c i c;
+ fprintf fmt "\n if w0_eq0 wy then x\n";
+ fprintf fmt " else w%i_sub wx " i;
+ if i = 1 then fprintf fmt "(WW w_0 wy)\n"
+ else fprintf fmt "(extend%i w0 (WW w_0 wy))\n" (i-1);
+ for j = 1 to size do
+ fprintf fmt " | %s%i wx, %s%i wy => " c i c j;
+ if i < j then fprintf fmt "w%i_sub (extend%i w%i wx) wy\n" j (j-i) (i-1)
+ else if i = j then fprintf fmt "w%i_sub wx wy\n" j
+ else fprintf fmt "w%i_sub wx (extend%i w%i wy)\n" i (i-j) (j-1)
+ done;
+ fprintf fmt
+ " | %s%i wx, %sn n wy => subn n (extend n w%i (extend%i w%i wx)) wy\n"
+ c i c size (size-i+1) (i-1)
+ done;
+ fprintf fmt " | %sn n wx, %s0 wy =>\n" c c;
+ fprintf fmt " if w0_eq0 wy then x\n";
+ fprintf fmt " else subn n wx (extend n w%i (extend%i w0 (WW w_0 wy)))\n"
+ size size;
+ for j = 1 to size do
+ fprintf fmt
+ " | %sn n wx, %s%i wy => subn n wx (extend n w%i (extend%i w%i wy))\n"
+ c c j size (size-j+1) (j-1);
+ done;
+ fprintf fmt " | %sn n wx, %sn m wy =>\n" c c;
+ fprintf fmt " match extend_to_max w%i n m wx wy with\n" size;
+ fprintf fmt " | inl wx' => subn m wx' wy\n";
+ fprintf fmt " | inr wy' => subn n wx wy'\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition compare_%i := w%i_op.(znz_compare).\n" i i;
+ fprintf fmt " Definition comparen_%i :=\n" i;
+ let s0 = if i = 0 then "w_0" else "W0" in
+ fprintf fmt
+ " compare_mn_1 w%i w%i %s compare_%i (compare_%i %s) compare_%i.\n"
+ i i s0 i i s0 i
+ done;
+ fprintf fmt "\n";
+
+ (* Comparison *)
+ fprintf fmt " Definition compare x y :=\n";
+ fprintf fmt " match x, y with\n";
+ for i = 0 to size do
+ for j = 0 to size do
+ fprintf fmt " | %s%i wx, %s%i wy => " c i c j;
+ if i < j then fprintf fmt "opp_compare (comparen_%i %i wy wx)\n" i (j-i)
+ else if i = j then fprintf fmt "compare_%i wx wy\n" i
+ else fprintf fmt "comparen_%i %i wx wy\n" j (i-j)
+ done;
+ let s0 = if i = 0 then "w_0" else "W0" in
+ fprintf fmt " | %s%i wx, %sn n wy =>\n" c i c;
+ fprintf fmt " opp_compare (compare_mn_1 w%i w%i %s " size i s0;
+ fprintf fmt "compare_%i (compare_%i W0) (comparen_%i %i) (S n) wy wx)\n"
+ i size i (size - i)
+ done;
+ for j = 0 to size do
+ let s0 = if j = 0 then "w_0" else "W0" in
+ fprintf fmt " | %sn n wx, %s%i wy =>\n" c c j;
+ fprintf fmt " compare_mn_1 w%i w%i %s " size j s0;
+ fprintf fmt "compare_%i (compare_%i W0) (comparen_%i %i) (S n) wx wy\n"
+ j size j (size - j)
+ done;
+ fprintf fmt " | %sn n wx, %sn m wy =>\n" c c;
+ fprintf fmt " match extend_to_max w%i n m wx wy with\n" size;
+ fprintf fmt
+ " | inl wx' => let op := make_op m in op.(znz_compare) wx' wy \n";
+ fprintf fmt
+ " | inr wy' => let op := make_op n in op.(znz_compare) wx wy' \n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition eq_bool x y :=\n";
+ fprintf fmt " match compare x y with\n";
+ fprintf fmt " | Eq => true\n";
+ fprintf fmt " | _ => false\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+
+ (* Multiplication *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_mul_c := w%i_op.(znz_mul_c).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ let s0 = if i = 0 then "w_0" else "W0" in
+ fprintf fmt " Definition w%i_mul_add :=\n" i;
+ fprintf fmt " Eval lazy beta delta [w_mul_add] in\n";
+ fprintf fmt " %sw_mul_add w%i %s w%i_succ w%i_add_c w%i_mul_c.\n"
+ "@" i s0 i i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ let s0 = if i = 0 then "w_0" else "W0" in
+ fprintf fmt " Definition w%i_mul_add_n1 :=\n" i;
+ fprintf fmt
+ " %sgen_mul_add_n1 w%i %s w%i_op.(znz_WW) w%i_0W w%i_mul_add.\n"
+ "@" i s0 i i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition mul x y :=\n";
+ fprintf fmt " match x, y with\n";
+ fprintf fmt " | %s0 wx, %s0 wy =>\n" c c;
+ fprintf fmt " reduce_1 (w0_mul_c wx wy)\n";
+ for j = 1 to size do
+ fprintf fmt " | %s0 wx, %s%i wy =>\n" c c j;
+ fprintf fmt " if w0_eq0 wx then zero\n";
+ fprintf fmt " else\n";
+ fprintf fmt " let (w,r) := w0_mul_add_n1 %i wy wx w_0 in\n" j;
+ fprintf fmt " if w0_eq0 w then %s%i r\n" c j;
+ if j = 1 then
+ fprintf fmt " else %s2 (WW (WW w_0 w) r)\n" c
+ else if j = size then
+ fprintf fmt " else %sn 0 (WW (extend%i w0 (WW w_0 w)) r)\n"
+ c (size-1)
+ else
+ fprintf fmt " else %s%i (WW (extend%i w0 (WW w_0 w)) r)\n"
+ c (j+1) (j-1)
+ done;
+
+ fprintf fmt " | %s0 wx, %sn n wy =>\n" c c;
+ fprintf fmt " if w0_eq0 wx then zero\n";
+ fprintf fmt " else\n";
+ fprintf fmt " let (w,r) := w%i_mul_add_n1 (S n) wy " size;
+ fprintf fmt "(extend%i w0 (WW w_0 wx)) W0 in\n" (size - 1);
+ fprintf fmt " if w%i_eq0 w then %sn n r\n" size c;
+ fprintf fmt " else %sn (S n) (WW (extend n w%i (WW W0 w)) r)\n" c size;
+
+ for i = 1 to size do
+ fprintf fmt " | %s%i wx, %s0 wy =>\n" c i c;
+ fprintf fmt " if w0_eq0 wy then zero\n";
+ fprintf fmt " else\n";
+ fprintf fmt " let (w,r) := w0_mul_add_n1 %i wx wy w_0 in\n" i;
+ fprintf fmt " if w0_eq0 w then %s%i r\n" c i;
+ if i = 1 then
+ fprintf fmt " else %s2 (WW (WW w_0 w) r)\n" c
+ else if i = size then
+ fprintf fmt " else %sn 0 (WW (extend%i w0 (WW w_0 w)) r)\n"
+ c (size-1)
+ else
+ fprintf fmt " else %s%i (WW (extend%i w0 (WW w_0 w)) r)\n"
+ c (i+1) (i-1);
+ for j = 1 to size do
+ fprintf fmt " | %s%i wx, %s%i wy =>\n" c i c j;
+ if i = j then begin
+ if i = size then fprintf fmt " %sn 0 (w%i_mul_c wx wy)\n" c i
+ else fprintf fmt " %s%i (w%i_mul_c wx wy)\n" c (i+1) i
+ end else begin
+ let min,max, wmin, wmax =
+ if i < j then i, j, "wx", "wy" else j, i, "wy", "wx" in
+ fprintf fmt " let (w,r) := w%i_mul_add_n1 %i %s %s W0 in\n"
+ min (max-min) wmax wmin;
+ fprintf fmt " if w%i_eq0 w then %s%i r\n" min c max;
+ fprintf fmt " else ";
+ if max = size then fprintf fmt "%sn 0 " c
+ else fprintf fmt "%s%i " c (max+1);
+ fprintf fmt "(WW (extend%i w%i w) r)\n" (max - min) (min-1);
+ end
+ done;
+ fprintf fmt " | %s%i wx, %sn n wy =>\n" c i c;
+ fprintf fmt " let (w,r) := w%i_mul_add_n1 (S n) wy " size;
+ if i = size then fprintf fmt "wx W0 in\n"
+ else
+ fprintf fmt "(extend%i w%i wx) W0 in\n" (size - i) (i-1);
+ fprintf fmt " if w%i_eq0 w then %sn n r\n" size c;
+ fprintf fmt " else %sn (S n) (WW (extend n w%i (WW W0 w)) r)\n" c size
+
+ done;
+ fprintf fmt " | %sn n wx, %s0 wy =>\n" c c;
+ fprintf fmt " if w0_eq0 wy then zero\n";
+ fprintf fmt " else\n";
+ fprintf fmt " let (w,r) := w%i_mul_add_n1 (S n) wx " size;
+ fprintf fmt "(extend%i w0 (WW w_0 wy)) W0 in\n" (size - 1);
+ fprintf fmt " if w%i_eq0 w then %sn n r\n" size c;
+ fprintf fmt " else %sn (S n) (WW (extend n w%i (WW W0 w)) r)\n" c size;
+
+ for j = 1 to size do
+ fprintf fmt " | %sn n wx, %s%i wy =>\n" c c j;
+ fprintf fmt " let (w,r) := w%i_mul_add_n1 (S n) wx " size;
+ if j = size then fprintf fmt "wy W0 in\n"
+ else
+ fprintf fmt "(extend%i w%i wy) W0 in\n" (size - j) (j-1);
+ fprintf fmt " if w%i_eq0 w then %sn n r\n" size c;
+ fprintf fmt " else %sn (S n) (WW (extend n w%i (WW W0 w)) r)\n" c size
+ done;
+
+ fprintf fmt " | %sn n wx, %sn m wy =>\n" c c;
+ fprintf fmt " match extend_to_max w%i n m wx wy with\n" size;
+ fprintf fmt " | inl wx' =>\n";
+ fprintf fmt " let op := make_op m in\n";
+ fprintf fmt " reduce_n (S m) (op.(znz_mul_c) wx' wy)\n";
+ fprintf fmt " | inr wy' =>\n";
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " reduce_n (S n) (op.(znz_mul_c) wx wy')\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ (* Square *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_square_c := w%i_op.(znz_square_c).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition square x :=\n";
+ fprintf fmt " match x with\n";
+ fprintf fmt " | %s0 wx => reduce_1 (w0_square_c wx)\n" c;
+ for i = 1 to size - 1 do
+ fprintf fmt " | %s%i wx => %s%i (w%i_square_c wx)\n" c i c (i+1) i
+ done;
+ fprintf fmt " | %s%i wx => %sn 0 (w%i_square_c wx)\n" c size c size;
+ fprintf fmt " | %sn n wx =>\n" c;
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " %sn (S n) (op.(znz_square_c) wx)\n" c;
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Fixpoint power_pos (x:%s) (p:positive) {struct p} : %s :=\n"
+ t t;
+ fprintf fmt " match p with\n";
+ fprintf fmt " | xH => x\n";
+ fprintf fmt " | xO p => square (power_pos x p)\n";
+ fprintf fmt " | xI p => mul (square (power_pos x p)) x\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ (* Square root *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_sqrt := w%i_op.(znz_sqrt).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition sqrt x :=\n";
+ fprintf fmt " match x with\n";
+ for i = 0 to size do
+ fprintf fmt " | %s%i wx => reduce_%i (w%i_sqrt wx)\n" c i i i;
+ done;
+ fprintf fmt " | %sn n wx =>\n" c;
+ fprintf fmt " let op := make_op n in\n";
+ fprintf fmt " reduce_n n (op.(znz_sqrt) wx)\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+
+ (* Division *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_div_gt := w%i_op.(znz_div_gt).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_divn1 :=\n" i;
+ fprintf fmt " gen_divn1 w%i_op.(znz_digits) w%i_op.(znz_0)\n" i i;
+ fprintf fmt " w%i_op.(znz_WW) w%i_op.(znz_head0)\n" i i;
+ fprintf fmt " w%i_op.(znz_add_mul_div) w%i_op.(znz_div21).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition div_gt x y :=\n";
+ fprintf fmt " match x, y with\n";
+ for i = 0 to size do
+ for j = 0 to size do
+ fprintf fmt " | %s%i wx, %s%i wy =>" c i c j;
+ if i = j then
+ fprintf fmt
+ " let (q, r):= w%i_div_gt wx wy in (reduce_%i q, reduce_%i r)\n"
+ i i i
+ else if i > j then
+ fprintf fmt
+ " let (q, r):= w%i_divn1 %i wx wy in (reduce_%i q, reduce_%i r)\n"
+ j (i-j) i j
+ else begin (* i < j *)
+ fprintf fmt
+ "\n let wx':= GenBase.extend w%i_0W %i wx in\n"
+ i (j-i-1);
+ fprintf fmt " let (q, r):= w%i_div_gt wx' wy in\n" j;
+ fprintf fmt " (reduce_%i q, reduce_%i r)\n" j j;
+ end
+ done;
+ fprintf fmt " | %s%i wx, %sn n wy =>\n" c i c;
+ fprintf fmt
+ " let wx':= extend n w%i (GenBase.extend w%i_0W %i wx) in\n"
+ size i (size-i);
+ fprintf fmt " let (q, r):= (make_op n).(znz_div_gt) wx' wy in\n";
+ fprintf fmt " (reduce_n n q, reduce_n n r)\n";
+ done;
+ for j = 0 to size do
+ fprintf fmt " | %sn n wx, %s%i wy =>\n" c c j;
+ if j < size then
+ fprintf fmt " let wy':= GenBase.extend w%i_0W %i wy in\n"
+ j (size-j-1)
+ else
+ fprintf fmt " let wy':= wy in\n";
+ fprintf fmt " let (q, r):= w%i_divn1 (S n) wx wy' in\n" size;
+ fprintf fmt " (reduce_n n q, reduce_%i r)\n" size
+ done;
+ fprintf fmt " | %sn n wx, %sn m wy =>\n" c c;
+ fprintf fmt " match extend_to_max w%i n m wx wy with\n" size;
+ fprintf fmt " | inl wx' =>\n";
+ fprintf fmt " let (q, r):= (make_op m).(znz_div) wx' wy in\n";
+ fprintf fmt " (reduce_n m q, reduce_n m r)\n";
+ fprintf fmt " | inr wy' =>\n";
+ fprintf fmt " let (q, r):= (make_op n).(znz_div) wx wy' in\n";
+ fprintf fmt " (reduce_n n q, reduce_n n r)\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition div_eucl x y :=\n";
+ fprintf fmt " match compare x y with\n";
+ fprintf fmt " | Eq => (one, zero)\n";
+ fprintf fmt " | Lt => (zero, x)\n";
+ fprintf fmt " | Gt => div_gt x y\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition div x y := fst (div_eucl x y).\n";
+ fprintf fmt "\n";
+
+ (* Modulo *)
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_mod_gt := w%i_op.(znz_mod_gt).\n" i i
+ done;
+ fprintf fmt "\n";
+
+ for i = 0 to size do
+ fprintf fmt " Definition w%i_modn1 :=\n" i;
+ fprintf fmt " gen_modn1 w%i_op.(znz_digits) w%i_op.(znz_0)\n" i i;
+ fprintf fmt
+ " w%i_op.(znz_head0) w%i_op.(znz_add_mul_div) w%i_op.(znz_div21).\n"
+ i i i
+ done;
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition mod_gt x y :=\n";
+ fprintf fmt " match x, y with\n";
+ for i = 0 to size do
+ for j = 0 to size do
+ fprintf fmt " | %s%i wx, %s%i wy =>"
+ c i c j;
+ if i = j then
+ fprintf fmt " reduce_%i (w%i_mod_gt wx wy)\n" i i
+ else if i > j then
+ fprintf fmt
+ " reduce_%i (w%i_modn1 %i wx wy)\n" j j (i-j)
+ else begin (* i < j *)
+ fprintf fmt
+ "\n let wx':= GenBase.extend w%i_0W %i wx in\n"
+ i (j-i-1);
+ fprintf fmt " reduce_%i (w%i_mod_gt wx' wy)\n" j j;
+ end
+ done;
+ fprintf fmt " | %s%i wx, %sn n wy =>\n" c i c;
+ fprintf fmt
+ " let wx':= extend n w%i (GenBase.extend w%i_0W %i wx) in\n"
+ size i (size-i);
+ fprintf fmt " reduce_n n ((make_op n).(znz_mod_gt) wx' wy)\n";
+ done;
+ for j = 0 to size do
+ fprintf fmt " | %sn n wx, %s%i wy =>\n" c c j;
+ if j < size then
+ fprintf fmt " let wy':= GenBase.extend w%i_0W %i wy in\n"
+ j (size-j-1)
+ else
+ fprintf fmt " let wy':= wy in\n";
+ fprintf fmt " reduce_%i (w%i_modn1 (S n) wx wy')\n" size size;
+ done;
+ fprintf fmt " | %sn n wx, %sn m wy =>\n" c c;
+ fprintf fmt " match extend_to_max w%i n m wx wy with\n" size;
+ fprintf fmt " | inl wx' =>\n";
+ fprintf fmt " reduce_n m ((make_op m).(znz_mod_gt) wx' wy)\n";
+ fprintf fmt " | inr wy' =>\n";
+ fprintf fmt " reduce_n n ((make_op n).(znz_mod_gt) wx wy')\n";
+ fprintf fmt " end\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition modulo x y := \n";
+ fprintf fmt " match compare x y with\n";
+ fprintf fmt " | Eq => zero\n";
+ fprintf fmt " | Lt => x\n";
+ fprintf fmt " | Gt => mod_gt x y\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ (* Definition du gcd *)
+ fprintf fmt " Definition digits x :=\n";
+ fprintf fmt " match x with\n";
+ for i = 0 to size do
+ fprintf fmt " | %s%i _ => w%i_op.(znz_digits)\n" c i i;
+ done;
+ fprintf fmt " | %sn n _ => (make_op n).(znz_digits)\n" c;
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition gcd_gt_body a b cont :=\n";
+ fprintf fmt " match compare b zero with\n";
+ fprintf fmt " | Gt =>\n";
+ fprintf fmt " let r := mod_gt a b in\n";
+ fprintf fmt " match compare r zero with\n";
+ fprintf fmt " | Gt => cont r (mod_gt b r)\n";
+ fprintf fmt " | _ => b\n";
+ fprintf fmt " end\n";
+ fprintf fmt " | _ => a\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Fixpoint gcd_gt (p:positive) (cont:%s->%s->%s) (a b:%s) {struct p} : %s :=\n" t t t t t;
+ fprintf fmt " gcd_gt_body a b\n";
+ fprintf fmt " (fun a b =>\n";
+ fprintf fmt " match p with\n";
+ fprintf fmt " | xH => cont a b\n";
+ fprintf fmt " | xO p => gcd_gt p (gcd_gt p cont) a b\n";
+ fprintf fmt " | xI p => gcd_gt p (gcd_gt p cont) a b\n";
+ fprintf fmt " end).\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition gcd_cont a b :=\n";
+ fprintf fmt " match compare one b with\n";
+ fprintf fmt " | Eq => one\n";
+ fprintf fmt " | _ => a\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition gcd a b :=\n";
+ fprintf fmt " match compare a b with\n";
+ fprintf fmt " | Eq => a\n";
+ fprintf fmt " | Lt => gcd_gt (digits b) gcd_cont b a\n";
+ fprintf fmt " | Gt => gcd_gt (digits a) gcd_cont a b\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition of_pos x :=\n";
+ fprintf fmt " let h := nat_of_P (pheight x) in\n";
+ fprintf fmt " match h with\n";
+ let rec print_S s fmt i =
+ if i = 0 then fprintf fmt "%s" s
+ else fprintf fmt "(S %a)" (print_S s) (i-1)
+ in
+ for i = 0 to size do
+ fprintf fmt " | ";
+ print_S "O" fmt i;
+ fprintf fmt " => %s%i (snd (w%i_op.(znz_of_pos) x))\n" "reduce_" i i
+ done;
+ fprintf fmt " | _ =>\n";
+ fprintf fmt " let n := minus h %i in\n" (size+1);
+ fprintf fmt " %sn n (snd ((make_op n).(znz_of_pos) x))\n" "reduce_";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition of_N x :=\n";
+ fprintf fmt " match x with\n";
+ fprintf fmt " | BinNat.N0 => zero\n";
+ fprintf fmt " | Npos p => of_pos p\n";
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+ fprintf fmt " Definition to_Z x :=\n";
+ fprintf fmt " match x with\n";
+ for i = 0 to size do
+ fprintf fmt " | %s%i wx => w%i_op.(znz_to_Z) wx\n" c i i
+ done;
+ fprintf fmt " | %sn n wx => (make_op n).(znz_to_Z) wx\n" c;
+ fprintf fmt " end.\n";
+ fprintf fmt "\n";
+
+
+ fprintf fmt "End Make.\n";
+ fprintf fmt "\n";
+ pp_print_flush fmt ()
+
+
+
+let _ = print_Make ()
+
+