summaryrefslogtreecommitdiff
path: root/theories/Numbers
diff options
context:
space:
mode:
Diffstat (limited to 'theories/Numbers')
-rw-r--r--theories/Numbers/BigNumPrelude.v10
-rw-r--r--theories/Numbers/BinNums.v61
-rw-r--r--theories/Numbers/Cyclic/Abstract/CyclicAxioms.v486
-rw-r--r--theories/Numbers/Cyclic/Abstract/NZCyclic.v141
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleAdd.v4
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleBase.v80
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleCyclic.v425
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleDiv.v122
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleDivn1.v130
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleLift.v38
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleMul.v23
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleSqrt.v29
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleSub.v4
-rw-r--r--theories/Numbers/Cyclic/DoubleCyclic/DoubleType.v6
-rw-r--r--theories/Numbers/Cyclic/Int31/Cyclic31.v326
-rw-r--r--theories/Numbers/Cyclic/Int31/Int31.v26
-rw-r--r--theories/Numbers/Cyclic/Int31/Ring31.v11
-rw-r--r--theories/Numbers/Cyclic/ZModulo/ZModulo.v483
-rw-r--r--theories/Numbers/Integer/Abstract/ZAdd.v48
-rw-r--r--theories/Numbers/Integer/Abstract/ZAddOrder.v123
-rw-r--r--theories/Numbers/Integer/Abstract/ZAxioms.v102
-rw-r--r--theories/Numbers/Integer/Abstract/ZBase.v19
-rw-r--r--theories/Numbers/Integer/Abstract/ZBits.v1947
-rw-r--r--theories/Numbers/Integer/Abstract/ZDivEucl.v103
-rw-r--r--theories/Numbers/Integer/Abstract/ZDivFloor.v123
-rw-r--r--theories/Numbers/Integer/Abstract/ZDivTrunc.v596
-rw-r--r--theories/Numbers/Integer/Abstract/ZGcd.v274
-rw-r--r--theories/Numbers/Integer/Abstract/ZLcm.v471
-rw-r--r--theories/Numbers/Integer/Abstract/ZLt.v24
-rw-r--r--theories/Numbers/Integer/Abstract/ZMaxMin.v179
-rw-r--r--theories/Numbers/Integer/Abstract/ZMul.v17
-rw-r--r--theories/Numbers/Integer/Abstract/ZMulOrder.v91
-rw-r--r--theories/Numbers/Integer/Abstract/ZParity.v52
-rw-r--r--theories/Numbers/Integer/Abstract/ZPow.v124
-rw-r--r--theories/Numbers/Integer/Abstract/ZProperties.v25
-rw-r--r--theories/Numbers/Integer/Abstract/ZSgnAbs.v88
-rw-r--r--theories/Numbers/Integer/BigZ/BigZ.v114
-rw-r--r--theories/Numbers/Integer/BigZ/ZMake.v375
-rw-r--r--theories/Numbers/Integer/Binary/ZBinary.v121
-rw-r--r--theories/Numbers/Integer/NatPairs/ZNatPairs.v58
-rw-r--r--theories/Numbers/Integer/SpecViaZ/ZSig.v74
-rw-r--r--theories/Numbers/Integer/SpecViaZ/ZSigZAxioms.v334
-rw-r--r--theories/Numbers/NaryFunctions.v4
-rw-r--r--theories/Numbers/NatInt/NZAdd.v34
-rw-r--r--theories/Numbers/NatInt/NZAddOrder.v35
-rw-r--r--theories/Numbers/NatInt/NZAxioms.v42
-rw-r--r--theories/Numbers/NatInt/NZBase.v19
-rw-r--r--theories/Numbers/NatInt/NZBits.v64
-rw-r--r--theories/Numbers/NatInt/NZDiv.v112
-rw-r--r--theories/Numbers/NatInt/NZDomain.v121
-rw-r--r--theories/Numbers/NatInt/NZGcd.v307
-rw-r--r--theories/Numbers/NatInt/NZLog.v889
-rw-r--r--theories/Numbers/NatInt/NZMul.v37
-rw-r--r--theories/Numbers/NatInt/NZMulOrder.v221
-rw-r--r--theories/Numbers/NatInt/NZOrder.v129
-rw-r--r--theories/Numbers/NatInt/NZParity.v263
-rw-r--r--theories/Numbers/NatInt/NZPow.v411
-rw-r--r--theories/Numbers/NatInt/NZProperties.v8
-rw-r--r--theories/Numbers/NatInt/NZSqrt.v734
-rw-r--r--theories/Numbers/Natural/Abstract/NAdd.v22
-rw-r--r--theories/Numbers/Natural/Abstract/NAddOrder.v10
-rw-r--r--theories/Numbers/Natural/Abstract/NAxioms.v58
-rw-r--r--theories/Numbers/Natural/Abstract/NBase.v59
-rw-r--r--theories/Numbers/Natural/Abstract/NBits.v1463
-rw-r--r--theories/Numbers/Natural/Abstract/NDefOps.v177
-rw-r--r--theories/Numbers/Natural/Abstract/NDiv.v50
-rw-r--r--theories/Numbers/Natural/Abstract/NGcd.v213
-rw-r--r--theories/Numbers/Natural/Abstract/NIso.v21
-rw-r--r--theories/Numbers/Natural/Abstract/NLcm.v290
-rw-r--r--theories/Numbers/Natural/Abstract/NLog.v23
-rw-r--r--theories/Numbers/Natural/Abstract/NMaxMin.v135
-rw-r--r--theories/Numbers/Natural/Abstract/NMulOrder.v22
-rw-r--r--theories/Numbers/Natural/Abstract/NOrder.v43
-rw-r--r--theories/Numbers/Natural/Abstract/NParity.v63
-rw-r--r--theories/Numbers/Natural/Abstract/NPow.v160
-rw-r--r--theories/Numbers/Natural/Abstract/NProperties.v21
-rw-r--r--theories/Numbers/Natural/Abstract/NSqrt.v75
-rw-r--r--theories/Numbers/Natural/Abstract/NStrongRec.v44
-rw-r--r--theories/Numbers/Natural/Abstract/NSub.v44
-rw-r--r--theories/Numbers/Natural/BigN/BigN.v107
-rw-r--r--theories/Numbers/Natural/BigN/NMake.v1448
-rw-r--r--theories/Numbers/Natural/BigN/NMake_gen.ml3511
-rw-r--r--theories/Numbers/Natural/BigN/Nbasic.v223
-rw-r--r--theories/Numbers/Natural/Binary/NBinary.v141
-rw-r--r--theories/Numbers/Natural/Peano/NPeano.v806
-rw-r--r--theories/Numbers/Natural/SpecViaZ/NSig.v76
-rw-r--r--theories/Numbers/Natural/SpecViaZ/NSigNAxioms.v375
-rw-r--r--theories/Numbers/NumPrelude.v125
-rw-r--r--theories/Numbers/Rational/BigQ/BigQ.v66
-rw-r--r--theories/Numbers/Rational/BigQ/QMake.v127
-rw-r--r--theories/Numbers/Rational/SpecViaQ/QSig.v12
-rw-r--r--theories/Numbers/vo.itarget23
92 files changed, 15106 insertions, 6244 deletions
diff --git a/theories/Numbers/BigNumPrelude.v b/theories/Numbers/BigNumPrelude.v
index 510b6888..26850688 100644
--- a/theories/Numbers/BigNumPrelude.v
+++ b/theories/Numbers/BigNumPrelude.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: BigNumPrelude.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
(** * BigNumPrelude *)
(** Auxillary functions & theorems used for arbitrary precision efficient
@@ -102,7 +100,7 @@ Hint Resolve Zlt_gt Zle_ge Z_div_pos: zarith.
intros b x y (Hx1,Hx2) (Hy1,Hy2);split;auto with zarith.
apply Zle_trans with ((b-1)*(b-1)).
apply Zmult_le_compat;auto with zarith.
- apply Zeq_le;ring.
+ apply Zeq_le; ring.
Qed.
Lemma sum_mul_carry : forall xh xl yh yl wc cc beta,
@@ -315,7 +313,7 @@ Theorem Zmod_le_first: forall a b, 0 <= a -> 0 < b -> 0 <= a mod b <= a.
apply Zdiv_le_lower_bound;auto with zarith.
replace (2^p) with 0.
destruct x;compute;intro;discriminate.
- destruct p;trivial;discriminate z.
+ destruct p;trivial;discriminate.
Qed.
Lemma div_lt : forall p x y, 0 <= x < y -> x / 2^p < y.
@@ -327,7 +325,7 @@ Theorem Zmod_le_first: forall a b, 0 <= a -> 0 < b -> 0 <= a mod b <= a.
assert (0 < 2^p);auto with zarith.
replace (2^p) with 0.
destruct x;change (0<y);auto with zarith.
- destruct p;trivial;discriminate z.
+ destruct p;trivial;discriminate.
Qed.
Theorem Zgcd_div_pos a b:
diff --git a/theories/Numbers/BinNums.v b/theories/Numbers/BinNums.v
new file mode 100644
index 00000000..dfb2c502
--- /dev/null
+++ b/theories/Numbers/BinNums.v
@@ -0,0 +1,61 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** * Binary Numerical Datatypes *)
+
+Set Implicit Arguments.
+(* For compatibility, we will not use generic equality functions *)
+Local Unset Boolean Equality Schemes.
+
+Declare ML Module "z_syntax_plugin".
+
+(** [positive] is a datatype representing the strictly positive integers
+ in a binary way. Starting from 1 (represented by [xH]), one can
+ add a new least significant digit via [xO] (digit 0) or [xI] (digit 1).
+ Numbers in [positive] can also be denoted using a decimal notation;
+ e.g. [6%positive] abbreviates [xO (xI xH)] *)
+
+Inductive positive : Set :=
+ | xI : positive -> positive
+ | xO : positive -> positive
+ | xH : positive.
+
+Delimit Scope positive_scope with positive.
+Bind Scope positive_scope with positive.
+Arguments xO _%positive.
+Arguments xI _%positive.
+
+(** [N] is a datatype representing natural numbers in a binary way,
+ by extending the [positive] datatype with a zero.
+ Numbers in [N] can also be denoted using a decimal notation;
+ e.g. [6%N] abbreviates [Npos (xO (xI xH))] *)
+
+Inductive N : Set :=
+ | N0 : N
+ | Npos : positive -> N.
+
+Delimit Scope N_scope with N.
+Bind Scope N_scope with N.
+Arguments Npos _%positive.
+
+(** [Z] is a datatype representing the integers in a binary way.
+ An integer is either zero or a strictly positive number
+ (coded as a [positive]) or a strictly negative number
+ (whose opposite is stored as a [positive] value).
+ Numbers in [Z] can also be denoted using a decimal notation;
+ e.g. [(-6)%Z] abbreviates [Zneg (xO (xI xH))] *)
+
+Inductive Z : Set :=
+ | Z0 : Z
+ | Zpos : positive -> Z
+ | Zneg : positive -> Z.
+
+Delimit Scope Z_scope with Z.
+Bind Scope Z_scope with Z.
+Arguments Zpos _%positive.
+Arguments Zneg _%positive.
diff --git a/theories/Numbers/Cyclic/Abstract/CyclicAxioms.v b/theories/Numbers/Cyclic/Abstract/CyclicAxioms.v
index fa097802..59656eed 100644
--- a/theories/Numbers/Cyclic/Abstract/CyclicAxioms.v
+++ b/theories/Numbers/Cyclic/Abstract/CyclicAxioms.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(* $Id: CyclicAxioms.v 14641 2011-11-06 11:59:10Z herbelin $ *)
-
(** * Signature and specification of a bounded integer structure *)
(** This file specifies how to represent [Z/nZ] when [n=2^d],
@@ -26,352 +24,300 @@ Local Open Scope Z_scope.
(** First, a description via an operator record and a spec record. *)
-Section Z_nZ_Op.
-
- Variable znz : Type.
+Module ZnZ.
- Record znz_op := mk_znz_op {
+ Class Ops (t:Type) := MkOps {
(* Conversion functions with Z *)
- znz_digits : positive;
- znz_zdigits: znz;
- znz_to_Z : znz -> Z;
- znz_of_pos : positive -> N * znz; (* Euclidean division by [2^digits] *)
- znz_head0 : znz -> znz; (* number of digits 0 in front of the number *)
- znz_tail0 : znz -> znz; (* number of digits 0 at the bottom of the number *)
+ digits : positive;
+ zdigits: t;
+ to_Z : t -> Z;
+ of_pos : positive -> N * t; (* Euclidean division by [2^digits] *)
+ head0 : t -> t; (* number of digits 0 in front of the number *)
+ tail0 : t -> t; (* number of digits 0 at the bottom of the number *)
(* Basic numbers *)
- znz_0 : znz;
- znz_1 : znz;
- znz_Bm1 : znz; (* [2^digits-1], which is equivalent to [-1] *)
+ zero : t;
+ one : t;
+ minus_one : t; (* [2^digits-1], which is equivalent to [-1] *)
(* Comparison *)
- znz_compare : znz -> znz -> comparison;
- znz_eq0 : znz -> bool;
+ compare : t -> t -> comparison;
+ eq0 : t -> bool;
(* Basic arithmetic operations *)
- znz_opp_c : znz -> carry znz;
- znz_opp : znz -> znz;
- znz_opp_carry : znz -> znz; (* the carry is known 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;
+ opp_c : t -> carry t;
+ opp : t -> t;
+ opp_carry : t -> t; (* the carry is known to be -1 *)
+
+ succ_c : t -> carry t;
+ add_c : t -> t -> carry t;
+ add_carry_c : t -> t -> carry t;
+ succ : t -> t;
+ add : t -> t -> t;
+ add_carry : t -> t -> t;
+
+ pred_c : t -> carry t;
+ sub_c : t -> t -> carry t;
+ sub_carry_c : t -> t -> carry t;
+ pred : t -> t;
+ sub : t -> t -> t;
+ sub_carry : t -> t -> t;
+
+ mul_c : t -> t -> zn2z t;
+ mul : t -> t -> t;
+ square_c : t -> zn2z t;
(* Special divisions operations *)
- znz_div21 : znz -> znz -> znz -> znz*znz;
- znz_div_gt : znz -> znz -> znz * znz; (* specialized version of [znz_div] *)
- znz_div : znz -> znz -> znz * znz;
+ div21 : t -> t -> t -> t*t;
+ div_gt : t -> t -> t * t; (* specialized version of [div] *)
+ div : t -> t -> t * t;
- znz_mod_gt : znz -> znz -> znz; (* specialized version of [znz_mod] *)
- znz_mod : znz -> znz -> znz;
+ modulo_gt : t -> t -> t; (* specialized version of [mod] *)
+ modulo : t -> t -> t;
- znz_gcd_gt : znz -> znz -> znz; (* specialized version of [znz_gcd] *)
- znz_gcd : znz -> znz -> znz;
- (* [znz_add_mul_div p i j] is a combination of the [(digits-p)]
+ gcd_gt : t -> t -> t; (* specialized version of [gcd] *)
+ gcd : t -> t -> t;
+ (* [add_mul_div p i j] is a combination of the [(digits-p)]
low bits of [i] above the [p] high bits of [j]:
- [znz_add_mul_div p i j = i*2^p+j/2^(digits-p)] *)
- znz_add_mul_div : znz -> znz -> znz -> znz;
- (* [znz_pos_mod p i] is [i mod 2^p] *)
- znz_pos_mod : znz -> znz -> znz;
+ [add_mul_div p i j = i*2^p+j/2^(digits-p)] *)
+ add_mul_div : t -> t -> t -> t;
+ (* [pos_mod p i] is [i mod 2^p] *)
+ pos_mod : t -> t -> t;
- znz_is_even : znz -> bool;
+ is_even : t -> bool;
(* square root *)
- znz_sqrt2 : znz -> znz -> znz * carry znz;
- znz_sqrt : znz -> znz }.
-
-End Z_nZ_Op.
-
-Section Z_nZ_Spec.
- Variable w : Type.
- Variable w_op : znz_op w.
-
- Let w_digits := w_op.(znz_digits).
- Let w_zdigits := w_op.(znz_zdigits).
- 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_tail0 := w_op.(znz_tail0).
-
- Let w0 := w_op.(znz_0).
- Let w1 := w_op.(znz_1).
- Let wBm1 := w_op.(znz_Bm1).
-
- 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).
+ sqrt2 : t -> t -> t * carry t;
+ sqrt : t -> t }.
- 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).
+ Section Specs.
+ Context {t : Type}{ops : Ops t}.
- 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).
+ Notation "[| x |]" := (to_Z x) (at level 0, x at level 99).
- 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.
+ Let wB := base digits.
Notation "[+| c |]" :=
- (interp_carry 1 wB w_to_Z c) (at level 0, x at level 99).
+ (interp_carry 1 wB 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).
+ (interp_carry (-1) wB 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).
+ (zn2z_to_Z wB to_Z x) (at level 0, x at level 99).
- Record znz_spec := mk_znz_spec {
+ Class Specs := MkSpecs {
(* 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))|];
- spec_zdigits : [| w_zdigits |] = Zpos w_digits;
- spec_more_than_1_digit: 1 < Zpos w_digits;
+ Zpos p = (Z_of_N (fst (of_pos p)))*wB + [|(snd (of_pos p))|];
+ spec_zdigits : [| zdigits |] = Zpos digits;
+ spec_more_than_1_digit: 1 < Zpos digits;
(* Basic numbers *)
- spec_0 : [|w0|] = 0;
- spec_1 : [|w1|] = 1;
- spec_Bm1 : [|wBm1|] = wB - 1;
+ spec_0 : [|zero|] = 0;
+ spec_1 : [|one|] = 1;
+ spec_m1 : [|minus_one|] = wB - 1;
(* 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;
+ spec_compare : forall x y, compare x y = ([|x|] ?= [|y|]);
+ (* NB: the spec of [eq0] is deliberately partial,
+ see DoubleCyclic where [eq0 x = true <-> x = W0] *)
+ spec_eq0 : forall x, 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_opp_c : forall x, [-|opp_c x|] = -[|x|];
+ spec_opp : forall x, [|opp x|] = (-[|x|]) mod wB;
+ spec_opp_carry : forall x, [|opp_carry x|] = wB - [|x|] - 1;
+
+ spec_succ_c : forall x, [+|succ_c x|] = [|x|] + 1;
+ spec_add_c : forall x y, [+|add_c x y|] = [|x|] + [|y|];
+ spec_add_carry_c : forall x y, [+|add_carry_c x y|] = [|x|] + [|y|] + 1;
+ spec_succ : forall x, [|succ x|] = ([|x|] + 1) mod wB;
+ spec_add : forall x y, [|add x y|] = ([|x|] + [|y|]) mod wB;
spec_add_carry :
- forall x y, [|w_add_carry x y|] = ([|x|] + [|y|] + 1) mod wB;
+ forall x y, [|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_pred_c : forall x, [-|pred_c x|] = [|x|] - 1;
+ spec_sub_c : forall x y, [-|sub_c x y|] = [|x|] - [|y|];
+ spec_sub_carry_c : forall x y, [-|sub_carry_c x y|] = [|x|] - [|y|] - 1;
+ spec_pred : forall x, [|pred x|] = ([|x|] - 1) mod wB;
+ spec_sub : forall x y, [|sub x y|] = ([|x|] - [|y|]) mod wB;
spec_sub_carry :
- forall x y, [|w_sub_carry x y|] = ([|x|] - [|y|] - 1) mod wB;
+ forall x y, [|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|];
+ spec_mul_c : forall x y, [|| mul_c x y ||] = [|x|] * [|y|];
+ spec_mul : forall x y, [|mul x y|] = ([|x|] * [|y|]) mod wB;
+ spec_square_c : forall x, [|| 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
+ let (q,r) := 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
+ let (q,r) := 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
+ let (q,r) := 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_modulo_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
+ [|modulo_gt a b|] = [|a|] mod [|b|];
+ spec_modulo : forall a b, 0 < [|b|] ->
+ [|modulo 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|];
+ Zis_gcd [|a|] [|b|] [|gcd_gt a b|];
+ spec_gcd : forall a b, Zis_gcd [|a|] [|b|] [|gcd a b|];
(* shift operations *)
- spec_head00: forall x, [|x|] = 0 -> [|w_head0 x|] = Zpos w_digits;
+ spec_head00: forall x, [|x|] = 0 -> [|head0 x|] = Zpos digits;
spec_head0 : forall x, 0 < [|x|] ->
- wB/ 2 <= 2 ^ ([|w_head0 x|]) * [|x|] < wB;
- spec_tail00: forall x, [|x|] = 0 -> [|w_tail0 x|] = Zpos w_digits;
+ wB/ 2 <= 2 ^ ([|head0 x|]) * [|x|] < wB;
+ spec_tail00: forall x, [|x|] = 0 -> [|tail0 x|] = Zpos digits;
spec_tail0 : forall x, 0 < [|x|] ->
- exists y, 0 <= y /\ [|x|] = (2 * y + 1) * (2 ^ [|w_tail0 x|]) ;
+ exists y, 0 <= y /\ [|x|] = (2 * y + 1) * (2 ^ [|tail0 x|]) ;
spec_add_mul_div : forall x y p,
- [|p|] <= Zpos w_digits ->
- [| w_add_mul_div p x y |] =
+ [|p|] <= Zpos digits ->
+ [| add_mul_div p x y |] =
([|x|] * (2 ^ [|p|]) +
- [|y|] / (2 ^ ((Zpos w_digits) - [|p|]))) mod wB;
+ [|y|] / (2 ^ ((Zpos digits) - [|p|]))) mod wB;
spec_pos_mod : forall w p,
- [|w_pos_mod p w|] = [|w|] mod (2 ^ [|p|]);
+ [|pos_mod p w|] = [|w|] mod (2 ^ [|p|]);
(* sqrt *)
spec_is_even : forall x,
- if w_is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1;
+ if 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
+ let (s,r) := 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
+ [|sqrt x|] ^ 2 <= [|x|] < ([|sqrt x|] + 1) ^ 2
}.
-End Z_nZ_Spec.
+ End Specs.
+
+ Arguments Specs {t} ops.
+
+ (** Generic construction of double words *)
-(** Generic construction of double words *)
+ Section WW.
-Section WW.
+ Context {t : Type}{ops : Ops t}{specs : Specs ops}.
- Variable w : Type.
- Variable w_op : znz_op w.
- Variable op_spec : znz_spec w_op.
+ Let wB := base digits.
- Let wB := base w_op.(znz_digits).
- Let w_to_Z := w_op.(znz_to_Z).
- Let w_eq0 := w_op.(znz_eq0).
- Let w_0 := w_op.(znz_0).
+ Definition WO' (eq0:t->bool) zero h :=
+ if eq0 h then W0 else WW h zero.
- Definition znz_W0 h :=
- if w_eq0 h then W0 else WW h w_0.
+ Definition WO := Eval lazy beta delta [WO'] in
+ let eq0 := ZnZ.eq0 in
+ let zero := ZnZ.zero in
+ WO' eq0 zero.
- Definition znz_0W l :=
- if w_eq0 l then W0 else WW w_0 l.
+ Definition OW' (eq0:t->bool) zero l :=
+ if eq0 l then W0 else WW zero l.
- Definition znz_WW h l :=
- if w_eq0 h then znz_0W l else WW h l.
+ Definition OW := Eval lazy beta delta [OW'] in
+ let eq0 := ZnZ.eq0 in
+ let zero := ZnZ.zero in
+ OW' eq0 zero.
- Lemma spec_W0 : forall h,
- zn2z_to_Z wB w_to_Z (znz_W0 h) = (w_to_Z h)*wB.
+ Definition WW' (eq0:t->bool) zero h l :=
+ if eq0 h then OW' eq0 zero l else WW h l.
+
+ Definition WW := Eval lazy beta delta [WW' OW'] in
+ let eq0 := ZnZ.eq0 in
+ let zero := ZnZ.zero in
+ WW' eq0 zero.
+
+ Lemma spec_WO : forall h,
+ zn2z_to_Z wB to_Z (WO h) = (to_Z h)*wB.
Proof.
- unfold zn2z_to_Z, znz_W0, w_to_Z; simpl; intros.
- case_eq (w_eq0 h); intros.
- rewrite (op_spec.(spec_eq0) _ H); auto.
- unfold w_0; rewrite op_spec.(spec_0); auto with zarith.
+ unfold zn2z_to_Z, WO; simpl; intros.
+ case_eq (eq0 h); intros.
+ rewrite (spec_eq0 _ H); auto.
+ rewrite spec_0; auto with zarith.
Qed.
- Lemma spec_0W : forall l,
- zn2z_to_Z wB w_to_Z (znz_0W l) = w_to_Z l.
+ Lemma spec_OW : forall l,
+ zn2z_to_Z wB to_Z (OW l) = to_Z l.
Proof.
- unfold zn2z_to_Z, znz_0W, w_to_Z; simpl; intros.
- case_eq (w_eq0 l); intros.
- rewrite (op_spec.(spec_eq0) _ H); auto.
- unfold w_0; rewrite op_spec.(spec_0); auto with zarith.
+ unfold zn2z_to_Z, OW; simpl; intros.
+ case_eq (eq0 l); intros.
+ rewrite (spec_eq0 _ H); auto.
+ rewrite spec_0; auto with zarith.
Qed.
Lemma spec_WW : forall h l,
- zn2z_to_Z wB w_to_Z (znz_WW h l) = (w_to_Z h)*wB + w_to_Z l.
+ zn2z_to_Z wB to_Z (WW h l) = (to_Z h)*wB + to_Z l.
Proof.
- unfold znz_WW, w_to_Z; simpl; intros.
- case_eq (w_eq0 h); intros.
- rewrite (op_spec.(spec_eq0) _ H); auto.
- rewrite spec_0W; auto.
+ unfold WW; simpl; intros.
+ case_eq (eq0 h); intros.
+ rewrite (spec_eq0 _ H); auto.
+ fold (OW l).
+ rewrite spec_OW; auto.
simpl; auto.
Qed.
-End WW.
-
-(** Injecting [Z] numbers into a cyclic structure *)
+ End WW.
-Section znz_of_pos.
+ (** Injecting [Z] numbers into a cyclic structure *)
- Variable w : Type.
- Variable w_op : znz_op w.
- Variable op_spec : znz_spec w_op.
+ Section Of_Z.
- Notation "[| x |]" := (znz_to_Z w_op x) (at level 0, x at level 99).
+ Context {t : Type}{ops : Ops t}{specs : Specs ops}.
- Definition znz_of_Z (w:Type) (op:znz_op w) z :=
- match z with
- | Zpos p => snd (op.(znz_of_pos) p)
- | _ => op.(znz_0)
- end.
+ Notation "[| x |]" := (to_Z x) (at level 0, x at level 99).
- Theorem znz_of_pos_correct:
- forall p, Zpos p < base (znz_digits w_op) -> [|(snd (znz_of_pos w_op p))|] = Zpos p.
+ Theorem of_pos_correct:
+ forall p, Zpos p < base digits -> [|(snd (of_pos p))|] = Zpos p.
+ Proof.
intros p Hp.
- generalize (spec_of_pos op_spec p).
- case (znz_of_pos w_op p); intros n w1; simpl.
+ generalize (spec_of_pos p).
+ case (of_pos 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.
+ replace (base digits) with (1 * base digits + 0) by ring.
+ rewrite Hp1.
+ apply Zplus_le_compat.
+ apply Zmult_le_compat; auto with zarith.
case p1; simpl; intros; red; simpl; intros; discriminate.
unfold base; auto with zarith.
- case (spec_to_Z op_spec w1); auto with zarith.
+ case (spec_to_Z 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.
+ Definition of_Z z :=
+ match z with
+ | Zpos p => snd (of_pos p)
+ | _ => zero
+ end.
+
+ Theorem of_Z_correct:
+ forall p, 0 <= p < base digits -> [|of_Z p|] = p.
+ Proof.
intros p; case p; simpl; try rewrite spec_0; auto.
- intros; rewrite znz_of_pos_correct; auto with zarith.
+ intros; rewrite of_pos_correct; auto with zarith.
intros p1 (H1, _); contradict H1; apply Zlt_not_le; red; simpl; auto.
Qed.
-End znz_of_pos.
+ End Of_Z.
+
+End ZnZ.
(** A modular specification grouping the earlier records. *)
Module Type CyclicType.
- Parameter w : Type.
- Parameter w_op : znz_op w.
- Parameter w_spec : znz_spec w_op.
+ Parameter t : Type.
+ Declare Instance ops : ZnZ.Ops t.
+ Declare Instance specs : ZnZ.Specs ops.
End CyclicType.
@@ -379,38 +325,29 @@ End CyclicType.
Module CyclicRing (Import Cyclic : CyclicType).
-Definition t := w.
-
-Local Notation "[| x |]" := (w_op.(znz_to_Z) x) (at level 0, x at level 99).
+Local Notation "[| x |]" := (ZnZ.to_Z x) (at level 0, x at level 99).
Definition eq (n m : t) := [| n |] = [| m |].
-Definition zero : t := w_op.(znz_0).
-Definition one := w_op.(znz_1).
-Definition add := w_op.(znz_add).
-Definition sub := w_op.(znz_sub).
-Definition mul := w_op.(znz_mul).
-Definition opp := w_op.(znz_opp).
Local Infix "==" := eq (at level 70).
-Local Notation "0" := zero.
-Local Notation "1" := one.
-Local Infix "+" := add.
-Local Infix "-" := sub.
-Local Infix "*" := mul.
-Local Notation "!!" := (base (znz_digits w_op)).
-
-Hint Rewrite
- w_spec.(spec_0) w_spec.(spec_1)
- w_spec.(spec_add) w_spec.(spec_mul) w_spec.(spec_opp) w_spec.(spec_sub)
+Local Notation "0" := ZnZ.zero.
+Local Notation "1" := ZnZ.one.
+Local Infix "+" := ZnZ.add.
+Local Infix "-" := ZnZ.sub.
+Local Notation "- x" := (ZnZ.opp x).
+Local Infix "*" := ZnZ.mul.
+Local Notation wB := (base ZnZ.digits).
+
+Hint Rewrite ZnZ.spec_0 ZnZ.spec_1 ZnZ.spec_add ZnZ.spec_mul
+ ZnZ.spec_opp ZnZ.spec_sub
: cyclic.
-Ltac zify :=
- unfold eq, zero, one, add, sub, mul, opp in *; autorewrite with cyclic.
+Ltac zify := unfold eq in *; autorewrite with cyclic.
Lemma add_0_l : forall x, 0 + x == x.
Proof.
intros. zify. rewrite Zplus_0_l.
-apply Zmod_small. apply w_spec.(spec_to_Z).
+apply Zmod_small. apply ZnZ.spec_to_Z.
Qed.
Lemma add_comm : forall x y, x + y == y + x.
@@ -426,7 +363,7 @@ Qed.
Lemma mul_1_l : forall x, 1 * x == x.
Proof.
intros. zify. rewrite Zmult_1_l.
-apply Zmod_small. apply w_spec.(spec_to_Z).
+apply Zmod_small. apply ZnZ.spec_to_Z.
Qed.
Lemma mul_comm : forall x y, x * y == y * x.
@@ -444,22 +381,22 @@ Proof.
intros. zify. now rewrite <- Zplus_mod, Zmult_mod_idemp_l, Zmult_plus_distr_l.
Qed.
-Lemma add_opp_r : forall x y, x + opp y == x-y.
+Lemma add_opp_r : forall x y, x + - y == x-y.
Proof.
intros. zify. rewrite <- Zminus_mod_idemp_r. unfold Zminus.
-destruct (Z_eq_dec ([|y|] mod !!) 0) as [EQ|NEQ].
+destruct (Z_eq_dec ([|y|] mod wB) 0) as [EQ|NEQ].
rewrite Z_mod_zero_opp_full, EQ, 2 Zplus_0_r; auto.
rewrite Z_mod_nz_opp_full by auto.
rewrite <- Zplus_mod_idemp_r, <- Zminus_mod_idemp_l.
rewrite Z_mod_same_full. simpl. now rewrite Zplus_mod_idemp_r.
Qed.
-Lemma add_opp_diag_r : forall x, x + opp x == 0.
+Lemma add_opp_diag_r : forall x, x + - x == 0.
Proof.
intros. red. rewrite add_opp_r. zify. now rewrite Zminus_diag, Zmod_0_l.
Qed.
-Lemma CyclicRing : ring_theory 0 1 add mul sub opp eq.
+Lemma CyclicRing : ring_theory 0 1 ZnZ.add ZnZ.mul ZnZ.sub ZnZ.opp eq.
Proof.
constructor.
exact add_0_l. exact add_comm. exact add_assoc.
@@ -470,15 +407,26 @@ exact add_opp_diag_r.
Qed.
Definition eqb x y :=
- match w_op.(znz_compare) x y with Eq => true | _ => false end.
+ match ZnZ.compare x y with Eq => true | _ => false end.
+
+Lemma eqb_eq : forall x y, eqb x y = true <-> x == y.
+Proof.
+ intros. unfold eqb, eq.
+ rewrite ZnZ.spec_compare.
+ case Zcompare_spec; intuition; try discriminate.
+Qed.
+(* POUR HUGO:
Lemma eqb_eq : forall x y, eqb x y = true <-> x == y.
Proof.
- intros. unfold eqb, eq. generalize (w_spec.(spec_compare) x y).
- destruct (w_op.(znz_compare) x y); intuition; try discriminate.
+ intros. unfold eqb, eq. generalize (ZnZ.spec_compare x y).
+ case (ZnZ.compare x y); intuition; try discriminate.
+ (* BUG ?! using destruct instead of case won't work:
+ it gives 3 subcases, but ZnZ.compare x y is still there in them! *)
Qed.
+*)
Lemma eqb_correct : forall x y, eqb x y = true -> x==y.
Proof. now apply eqb_eq. Qed.
-End CyclicRing. \ No newline at end of file
+End CyclicRing.
diff --git a/theories/Numbers/Cyclic/Abstract/NZCyclic.v b/theories/Numbers/Cyclic/Abstract/NZCyclic.v
index 92215ba9..c52cbe10 100644
--- a/theories/Numbers/Cyclic/Abstract/NZCyclic.v
+++ b/theories/Numbers/Cyclic/Abstract/NZCyclic.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZCyclic.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NZAxioms.
Require Import BigNumPrelude.
Require Import DoubleType.
@@ -27,21 +25,19 @@ Module NZCyclicAxiomsMod (Import Cyclic : CyclicType) <: NZAxiomsSig.
Local Open Scope Z_scope.
-Definition t := w.
-
-Definition NZ_to_Z : t -> Z := znz_to_Z w_op.
-Definition Z_to_NZ : Z -> t := znz_of_Z w_op.
-Local Notation wB := (base w_op.(znz_digits)).
+Local Notation wB := (base ZnZ.digits).
-Local Notation "[| x |]" := (w_op.(znz_to_Z) x) (at level 0, x at level 99).
+Local Notation "[| x |]" := (ZnZ.to_Z x) (at level 0, x at level 99).
Definition eq (n m : t) := [| n |] = [| m |].
-Definition zero := w_op.(znz_0).
-Definition succ := w_op.(znz_succ).
-Definition pred := w_op.(znz_pred).
-Definition add := w_op.(znz_add).
-Definition sub := w_op.(znz_sub).
-Definition mul := w_op.(znz_mul).
+Definition zero := ZnZ.zero.
+Definition one := ZnZ.one.
+Definition two := ZnZ.succ ZnZ.one.
+Definition succ := ZnZ.succ.
+Definition pred := ZnZ.pred.
+Definition add := ZnZ.add.
+Definition sub := ZnZ.sub.
+Definition mul := ZnZ.mul.
Local Infix "==" := eq (at level 70).
Local Notation "0" := zero.
@@ -51,41 +47,25 @@ Local Infix "+" := add.
Local Infix "-" := sub.
Local Infix "*" := mul.
-Hint Rewrite w_spec.(spec_0) w_spec.(spec_succ) w_spec.(spec_pred)
- w_spec.(spec_add) w_spec.(spec_mul) w_spec.(spec_sub) : w.
-Ltac wsimpl :=
- unfold eq, zero, succ, pred, add, sub, mul; autorewrite with w.
-Ltac wcongruence := repeat red; intros; wsimpl; congruence.
+Hint Rewrite ZnZ.spec_0 ZnZ.spec_1 ZnZ.spec_succ ZnZ.spec_pred
+ ZnZ.spec_add ZnZ.spec_mul ZnZ.spec_sub : cyclic.
+Ltac zify :=
+ unfold eq, zero, one, two, succ, pred, add, sub, mul in *;
+ autorewrite with cyclic.
+Ltac zcongruence := repeat red; intros; zify; congruence.
Instance eq_equiv : Equivalence eq.
Proof.
unfold eq. firstorder.
Qed.
-Instance succ_wd : Proper (eq ==> eq) succ.
-Proof.
-wcongruence.
-Qed.
-
-Instance pred_wd : Proper (eq ==> eq) pred.
-Proof.
-wcongruence.
-Qed.
-
-Instance add_wd : Proper (eq ==> eq ==> eq) add.
-Proof.
-wcongruence.
-Qed.
-
-Instance sub_wd : Proper (eq ==> eq ==> eq) sub.
-Proof.
-wcongruence.
-Qed.
+Local Obligation Tactic := zcongruence.
-Instance mul_wd : Proper (eq ==> eq ==> eq) mul.
-Proof.
-wcongruence.
-Qed.
+Program Instance succ_wd : Proper (eq ==> eq) succ.
+Program Instance pred_wd : Proper (eq ==> eq) pred.
+Program Instance add_wd : Proper (eq ==> eq ==> eq) add.
+Program Instance sub_wd : Proper (eq ==> eq ==> eq) sub.
+Program Instance mul_wd : Proper (eq ==> eq ==> eq) mul.
Theorem gt_wB_1 : 1 < wB.
Proof.
@@ -97,39 +77,41 @@ Proof.
pose proof gt_wB_1; auto with zarith.
Qed.
+Lemma one_mod_wB : 1 mod wB = 1.
+Proof.
+rewrite Zmod_small. reflexivity. split. auto with zarith. apply gt_wB_1.
+Qed.
+
Lemma succ_mod_wB : forall n : Z, (n + 1) mod wB = ((n mod wB) + 1) mod wB.
Proof.
-intro n.
-pattern 1 at 2. replace 1 with (1 mod wB). rewrite <- Zplus_mod.
-reflexivity.
-now rewrite Zmod_small; [ | split; [auto with zarith | apply gt_wB_1]].
+intro n. rewrite <- one_mod_wB at 2. now rewrite <- Zplus_mod.
Qed.
Lemma pred_mod_wB : forall n : Z, (n - 1) mod wB = ((n mod wB) - 1) mod wB.
Proof.
-intro n.
-pattern 1 at 2. replace 1 with (1 mod wB). rewrite <- Zminus_mod.
-reflexivity.
-now rewrite Zmod_small; [ | split; [auto with zarith | apply gt_wB_1]].
+intro n. rewrite <- one_mod_wB at 2. now rewrite Zminus_mod.
Qed.
Lemma NZ_to_Z_mod : forall n, [| n |] mod wB = [| n |].
Proof.
-intro n; rewrite Zmod_small. reflexivity. apply w_spec.(spec_to_Z).
+intro n; rewrite Zmod_small. reflexivity. apply ZnZ.spec_to_Z.
Qed.
Theorem pred_succ : forall n, P (S n) == n.
Proof.
-intro n. wsimpl.
+intro n. zify.
rewrite <- pred_mod_wB.
-replace ([| n |] + 1 - 1)%Z with [| n |] by auto with zarith. apply NZ_to_Z_mod.
+replace ([| n |] + 1 - 1)%Z with [| n |] by ring. apply NZ_to_Z_mod.
Qed.
-Lemma Z_to_NZ_0 : Z_to_NZ 0%Z == 0.
+Theorem one_succ : one == succ zero.
Proof.
-unfold NZ_to_Z, Z_to_NZ. wsimpl.
-rewrite znz_of_Z_correct; auto.
-exact w_spec. split; [auto with zarith |apply gt_wB_0].
+zify; simpl. now rewrite one_mod_wB.
+Qed.
+
+Theorem two_succ : two == succ one.
+Proof.
+reflexivity.
Qed.
Section Induction.
@@ -140,21 +122,22 @@ Hypothesis A0 : A 0.
Hypothesis AS : forall n, A n <-> A (S n).
(* Below, we use only -> direction *)
-Let B (n : Z) := A (Z_to_NZ n).
+Let B (n : Z) := A (ZnZ.of_Z n).
Lemma B0 : B 0.
Proof.
-unfold B. now rewrite Z_to_NZ_0.
+unfold B.
+setoid_replace (ZnZ.of_Z 0) with zero. assumption.
+red; zify. apply ZnZ.of_Z_correct. auto using gt_wB_0 with zarith.
Qed.
Lemma BS : forall n : Z, 0 <= n -> n < wB - 1 -> B n -> B (n + 1).
Proof.
intros n H1 H2 H3.
-unfold B in *. apply -> AS in H3.
-setoid_replace (Z_to_NZ (n + 1)) with (S (Z_to_NZ n)). assumption.
-wsimpl.
-unfold NZ_to_Z, Z_to_NZ.
-do 2 (rewrite znz_of_Z_correct; [ | exact w_spec | auto with zarith]).
+unfold B in *. apply AS in H3.
+setoid_replace (ZnZ.of_Z (n + 1)) with (S (ZnZ.of_Z n)). assumption.
+zify.
+rewrite 2 ZnZ.of_Z_correct; auto with zarith.
symmetry; apply Zmod_small; auto with zarith.
Qed.
@@ -167,25 +150,23 @@ Qed.
Theorem bi_induction : forall n, A n.
Proof.
-intro n. setoid_replace n with (Z_to_NZ (NZ_to_Z n)).
-apply B_holds. apply w_spec.(spec_to_Z).
-unfold eq, NZ_to_Z, Z_to_NZ; rewrite znz_of_Z_correct.
-reflexivity.
-exact w_spec.
-apply w_spec.(spec_to_Z).
+intro n. setoid_replace n with (ZnZ.of_Z (ZnZ.to_Z n)).
+apply B_holds. apply ZnZ.spec_to_Z.
+red. symmetry. apply ZnZ.of_Z_correct.
+apply ZnZ.spec_to_Z.
Qed.
End Induction.
Theorem add_0_l : forall n, 0 + n == n.
Proof.
-intro n. wsimpl.
-rewrite Zplus_0_l. rewrite Zmod_small; [reflexivity | apply w_spec.(spec_to_Z)].
+intro n. zify.
+rewrite Zplus_0_l. apply Zmod_small. apply ZnZ.spec_to_Z.
Qed.
Theorem add_succ_l : forall n m, (S n) + m == S (n + m).
Proof.
-intros n m. wsimpl.
+intros n m. zify.
rewrite succ_mod_wB. repeat rewrite Zplus_mod_idemp_l; try apply gt_wB_0.
rewrite <- (Zplus_assoc ([| n |] mod wB) 1 [| m |]). rewrite Zplus_mod_idemp_l.
rewrite (Zplus_comm 1 [| m |]); now rewrite Zplus_assoc.
@@ -193,25 +174,27 @@ Qed.
Theorem sub_0_r : forall n, n - 0 == n.
Proof.
-intro n. wsimpl. rewrite Zminus_0_r. apply NZ_to_Z_mod.
+intro n. zify. rewrite Zminus_0_r. apply NZ_to_Z_mod.
Qed.
Theorem sub_succ_r : forall n m, n - (S m) == P (n - m).
Proof.
-intros n m. wsimpl. rewrite Zminus_mod_idemp_r, Zminus_mod_idemp_l.
+intros n m. zify. rewrite Zminus_mod_idemp_r, Zminus_mod_idemp_l.
now replace ([|n|] - ([|m|] + 1))%Z with ([|n|] - [|m|] - 1)%Z
- by auto with zarith.
+ by ring.
Qed.
Theorem mul_0_l : forall n, 0 * n == 0.
Proof.
-intro n. wsimpl. now rewrite Zmult_0_l.
+intro n. now zify.
Qed.
Theorem mul_succ_l : forall n m, (S n) * m == n * m + m.
Proof.
-intros n m. wsimpl. rewrite Zplus_mod_idemp_l, Zmult_mod_idemp_l.
+intros n m. zify. rewrite Zplus_mod_idemp_l, Zmult_mod_idemp_l.
now rewrite Zmult_plus_distr_l, Zmult_1_l.
Qed.
+Definition t := t.
+
End NZCyclicAxiomsMod.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleAdd.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleAdd.v
index 305d77a9..deb216dd 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleAdd.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleAdd.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleAdd.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleBase.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleBase.v
index 3d44f96b..e6c5a0e0 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleBase.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleBase.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,16 +8,16 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleBase.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
-Require Import ZArith.
+Require Import ZArith Ndigits.
Require Import BigNumPrelude.
Require Import DoubleType.
Local Open Scope Z_scope.
+Local Infix "<<" := Pos.shiftl_nat (at level 30).
+
Section DoubleBase.
Variable w : Type.
Variable w_0 : w.
@@ -70,13 +70,7 @@ Section DoubleBase.
end
end.
- Fixpoint double_digits (n:nat) : positive :=
- match n with
- | O => w_digits
- | S n => xO (double_digits n)
- end.
-
- Definition double_wB n := base (double_digits n).
+ Definition double_wB n := base (w_digits << n).
Fixpoint double_to_Z (n:nat) : word w n -> Z :=
match n return word w n -> Z with
@@ -167,11 +161,7 @@ Section DoubleBase.
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.
+ w_compare x y = Zcompare [|x|] [|y|].
Lemma wwB_wBwB : wwB = wB^2.
Proof.
@@ -297,11 +287,10 @@ Section DoubleBase.
Lemma double_wB_wwB : forall n, double_wB n * double_wB n = double_wB (S n).
Proof.
intros n;unfold double_wB;simpl.
- unfold base;rewrite (Zpos_xO (double_digits n)).
- replace (2 * Zpos (double_digits n)) with
- (Zpos (double_digits n) + Zpos (double_digits n)).
+ unfold base. rewrite Pshiftl_nat_S, (Zpos_xO (_ << _)).
+ replace (2 * Zpos (w_digits << n)) with
+ (Zpos (w_digits << n) + Zpos (w_digits << n)) by ring.
symmetry; apply Zpower_exp;intro;discriminate.
- ring.
Qed.
Lemma double_wB_pos:
@@ -315,7 +304,7 @@ Section DoubleBase.
Proof.
clear spec_w_0 spec_w_1 spec_w_Bm1 w_0 w_1 w_Bm1.
intros n; elim n; clear n; auto.
- unfold double_wB, double_digits; auto with zarith.
+ unfold double_wB, "<<"; auto with zarith.
intros n H1; rewrite <- double_wB_wwB.
apply Zle_trans with (wB * 1).
rewrite Zmult_1_r; apply Zle_refl.
@@ -408,35 +397,40 @@ Section DoubleBase.
intros a b c d H1; apply beta_lex_inv with (1 := H1); auto.
Qed.
+ Ltac comp2ord := match goal with
+ | |- Lt = (?x ?= ?y) => symmetry; change (x < y)
+ | |- Gt = (?x ?= ?y) => symmetry; change (x > y); apply Zlt_gt
+ end.
+
Lemma spec_ww_compare : forall x y,
- match ww_compare x y with
- | Eq => [[x]] = [[y]]
- | Lt => [[x]] < [[y]]
- | Gt => [[x]] > [[y]]
- end.
+ ww_compare x y = Zcompare [[x]] [[y]].
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.
+ (* 1st case *)
+ rewrite 2 spec_w_compare, spec_w_0.
+ destruct (Zcompare_spec 0 [|yh|]) as [H|H|H].
+ rewrite <- H;simpl. reflexivity.
+ symmetry. change (0 < [|yh|]*wB+[|yl|]).
+ change 0 with (0*wB+0). rewrite <- spec_w_0 at 2.
apply wB_lex_inv;trivial.
- absurd (0 <= [|yh|]). apply Zgt_not_le;trivial.
+ absurd (0 <= [|yh|]). apply Zlt_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.
+ (* 2nd case *)
+ rewrite 2 spec_w_compare, spec_w_0.
+ destruct (Zcompare_spec [|xh|] 0) as [H|H|H].
+ rewrite H;simpl;reflexivity.
+ absurd (0 <= [|xh|]). apply Zlt_not_le; 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.
+ comp2ord.
+ change 0 with (0*wB+0). rewrite <- spec_w_0 at 2.
apply wB_lex_inv;trivial.
- apply Zlt_gt;apply wB_lex_inv;apply Zgt_lt;trivial.
+ (* 3rd case *)
+ rewrite 2 spec_w_compare.
+ destruct (Zcompare_spec [|xh|] [|yh|]) as [H|H|H].
+ rewrite H.
+ symmetry. apply Zcompare_plus_compat.
+ comp2ord. apply wB_lex_inv;trivial.
+ comp2ord. apply wB_lex_inv;trivial.
Qed.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleCyclic.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleCyclic.v
index 006da1b3..00a84052 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleCyclic.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleCyclic.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleCyclic.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
@@ -30,65 +28,65 @@ Local Open Scope Z_scope.
Section Z_2nZ.
- Variable w : Type.
- Variable w_op : znz_op w.
- Let w_digits := w_op.(znz_digits).
- Let w_zdigits := w_op.(znz_zdigits).
+ Context {t : Type}{ops : ZnZ.Ops t}.
+
+ Let w_digits := ZnZ.digits.
+ Let w_zdigits := ZnZ.zdigits.
- 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_tail0 := w_op.(znz_tail0).
+ Let w_to_Z := ZnZ.to_Z.
+ Let w_of_pos := ZnZ.of_pos.
+ Let w_head0 := ZnZ.head0.
+ Let w_tail0 := ZnZ.tail0.
- Let w_0 := w_op.(znz_0).
- Let w_1 := w_op.(znz_1).
- Let w_Bm1 := w_op.(znz_Bm1).
+ Let w_0 := ZnZ.zero.
+ Let w_1 := ZnZ.one.
+ Let w_Bm1 := ZnZ.minus_one.
- Let w_compare := w_op.(znz_compare).
- Let w_eq0 := w_op.(znz_eq0).
+ Let w_compare := ZnZ.compare.
+ Let w_eq0 := 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_opp_c := ZnZ.opp_c.
+ Let w_opp := ZnZ.opp.
+ Let w_opp_carry := 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_succ_c := ZnZ.succ_c.
+ Let w_add_c := ZnZ.add_c.
+ Let w_add_carry_c := ZnZ.add_carry_c.
+ Let w_succ := ZnZ.succ.
+ Let w_add := ZnZ.add.
+ Let w_add_carry := 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_pred_c := ZnZ.pred_c.
+ Let w_sub_c := ZnZ.sub_c.
+ Let w_sub_carry_c := ZnZ.sub_carry_c.
+ Let w_pred := ZnZ.pred.
+ Let w_sub := ZnZ.sub.
+ Let w_sub_carry := 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_mul_c := ZnZ.mul_c.
+ Let w_mul := ZnZ.mul.
+ Let w_square_c := 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_div21 := ZnZ.div21.
+ Let w_div_gt := ZnZ.div_gt.
+ Let w_div := ZnZ.div.
- Let w_mod_gt := w_op.(znz_mod_gt).
- Let w_mod := w_op.(znz_mod).
+ Let w_mod_gt := ZnZ.modulo_gt.
+ Let w_mod := ZnZ.modulo.
- Let w_gcd_gt := w_op.(znz_gcd_gt).
- Let w_gcd := w_op.(znz_gcd).
+ Let w_gcd_gt := ZnZ.gcd_gt.
+ Let w_gcd := ZnZ.gcd.
- Let w_add_mul_div := w_op.(znz_add_mul_div).
+ Let w_add_mul_div := ZnZ.add_mul_div.
- Let w_pos_mod := w_op.(znz_pos_mod).
+ Let w_pos_mod := 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 w_is_even := ZnZ.is_even.
+ Let w_sqrt2 := ZnZ.sqrt2.
+ Let w_sqrt := ZnZ.sqrt.
- Let _zn2z := zn2z w.
+ Let _zn2z := zn2z t.
Let wB := base w_digits.
@@ -105,9 +103,9 @@ Section Z_2nZ.
Let to_Z := zn2z_to_Z wB w_to_Z.
- Let w_W0 := znz_W0 w_op.
- Let w_0W := znz_0W w_op.
- Let w_WW := znz_WW w_op.
+ Let w_W0 := ZnZ.WO.
+ Let w_0W := ZnZ.OW.
+ Let w_WW := ZnZ.WW.
Let ww_of_pos p :=
match w_of_pos p with
@@ -124,15 +122,15 @@ Section Z_2nZ.
Eval lazy beta delta [ww_tail0] in
ww_tail0 w_0 w_0W w_compare w_tail0 w_add2 w_zdigits _ww_zdigits.
- 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).
+ Let ww_WW := Eval lazy beta delta [ww_WW] in (@ww_WW t).
+ Let ww_0W := Eval lazy beta delta [ww_0W] in (@ww_0W t).
+ Let ww_W0 := Eval lazy beta delta [ww_W0] in (@ww_W0 t).
(* ** Comparison ** *)
Let compare :=
Eval lazy beta delta[ww_compare] in ww_compare w_0 w_compare.
- Let eq0 (x:zn2z w) :=
+ Let eq0 (x:zn2z t) :=
match x with
| W0 => true
| _ => false
@@ -226,7 +224,7 @@ Section Z_2nZ.
Eval lazy beta iota delta [ww_div21] in
ww_div21 w_0 w_0W div32 ww_1 compare sub.
- Let low (p: zn2z w) := match p with WW _ p1 => p1 | _ => w_0 end.
+ Let low (p: zn2z t) := match p with WW _ p1 => p1 | _ => w_0 end.
Let add_mul_div :=
Eval lazy beta delta [ww_add_mul_div] in
@@ -287,8 +285,8 @@ Section Z_2nZ.
(* ** Record of operators on 2 words *)
- Definition mk_zn2z_op :=
- mk_znz_op _ww_digits _ww_zdigits
+ Global Instance mk_zn2z_ops : ZnZ.Ops (zn2z t) | 1 :=
+ ZnZ.MkOps _ww_digits _ww_zdigits
to_Z ww_of_pos head0 tail0
W0 ww_1 ww_Bm1
compare eq0
@@ -307,8 +305,8 @@ Section Z_2nZ.
sqrt2
sqrt.
- Definition mk_zn2z_op_karatsuba :=
- mk_znz_op _ww_digits _ww_zdigits
+ Global Instance mk_zn2z_ops_karatsuba : ZnZ.Ops (zn2z t) | 2 :=
+ ZnZ.MkOps _ww_digits _ww_zdigits
to_Z ww_of_pos head0 tail0
W0 ww_1 ww_Bm1
compare eq0
@@ -328,51 +326,51 @@ Section Z_2nZ.
sqrt.
(* Proof *)
- Variable op_spec : znz_spec w_op.
+ Context {specs : ZnZ.Specs ops}.
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_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_tail0 op_spec)
- (spec_add_mul_div op_spec)
- (spec_pos_mod)
- (spec_is_even)
- (spec_sqrt2)
- (spec_sqrt)
- (spec_W0 op_spec)
- (spec_0W op_spec)
- (spec_WW op_spec).
+ ZnZ.spec_to_Z
+ ZnZ.spec_of_pos
+ ZnZ.spec_0
+ ZnZ.spec_1
+ ZnZ.spec_m1
+ ZnZ.spec_compare
+ ZnZ.spec_eq0
+ ZnZ.spec_opp_c
+ ZnZ.spec_opp
+ ZnZ.spec_opp_carry
+ ZnZ.spec_succ_c
+ ZnZ.spec_add_c
+ ZnZ.spec_add_carry_c
+ ZnZ.spec_succ
+ ZnZ.spec_add
+ ZnZ.spec_add_carry
+ ZnZ.spec_pred_c
+ ZnZ.spec_sub_c
+ ZnZ.spec_sub_carry_c
+ ZnZ.spec_pred
+ ZnZ.spec_sub
+ ZnZ.spec_sub_carry
+ ZnZ.spec_mul_c
+ ZnZ.spec_mul
+ ZnZ.spec_square_c
+ ZnZ.spec_div21
+ ZnZ.spec_div_gt
+ ZnZ.spec_div
+ ZnZ.spec_modulo_gt
+ ZnZ.spec_modulo
+ ZnZ.spec_gcd_gt
+ ZnZ.spec_gcd
+ ZnZ.spec_head0
+ ZnZ.spec_tail0
+ ZnZ.spec_add_mul_div
+ ZnZ.spec_pos_mod
+ ZnZ.spec_is_even
+ ZnZ.spec_sqrt2
+ ZnZ.spec_sqrt
+ ZnZ.spec_WO
+ ZnZ.spec_OW
+ ZnZ.spec_WW.
Ltac wwauto := unfold ww_to_Z; auto.
@@ -395,16 +393,17 @@ Section Z_2nZ.
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, to_Z.
- rewrite (spec_WW op_spec).
+ rewrite (ZnZ.spec_of_pos p). unfold w_of_pos.
+ case (ZnZ.of_pos p); intros. simpl.
+ destruct n; simpl ZnZ.to_Z.
+ simpl;unfold w_to_Z,w_0; rewrite ZnZ.spec_0;trivial.
+ unfold Z_of_N.
+ rewrite (ZnZ.spec_of_pos p0).
+ case (ZnZ.of_pos p0); intros. simpl.
+ unfold fst, snd,Z_of_N, to_Z, wB, w_digits, w_to_Z, w_WW.
+ rewrite ZnZ.spec_WW.
replace wwB with (wB*wB).
- unfold wB,w_to_Z,w_digits;clear H;destruct n;ring.
+ unfold wB,w_to_Z,w_digits;destruct n;ring.
symmetry. rewrite <- Zpower_2; exact (wwB_wBwB w_digits).
Qed.
@@ -418,15 +417,9 @@ Section Z_2nZ.
Proof. refine (spec_ww_Bm1 w_Bm1 w_digits w_to_Z _);auto. Qed.
Let spec_ww_compare :
- forall x y,
- match compare x y with
- | Eq => [|x|] = [|y|]
- | Lt => [|x|] < [|y|]
- | Gt => [|x|] > [|y|]
- end.
+ forall x y, compare x y = Zcompare [|x|] [|y|].
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.
@@ -531,8 +524,7 @@ Section Z_2nZ.
Proof.
refine (spec_ww_karatsuba_c _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _); wwauto.
- unfold w_digits; apply spec_more_than_1_digit; auto.
- exact (spec_compare op_spec).
+ unfold w_digits; apply ZnZ.spec_more_than_1_digit; auto.
Qed.
Let spec_ww_mul : forall x y, [|mul x y|] = ([|x|] * [|y|]) mod wwB.
@@ -559,11 +551,10 @@ Section Z_2nZ.
w_add w_add_carry w_pred w_sub w_mul_c w_div21 sub_c w_digits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _);wwauto.
unfold w_Bm2, w_to_Z, w_pred, w_Bm1.
- rewrite (spec_pred op_spec);rewrite (spec_Bm1 op_spec).
+ rewrite ZnZ.spec_pred, ZnZ.spec_m1.
unfold w_digits;rewrite Zmod_small. ring.
- assert (H:= wB_pos(znz_digits w_op)). omega.
- exact (spec_compare op_spec).
- exact (spec_div21 op_spec).
+ assert (H:= wB_pos(ZnZ.digits)). omega.
+ exact ZnZ.spec_div21.
Qed.
Let spec_ww_div21 : forall a1 a2 b,
@@ -580,22 +571,19 @@ Section Z_2nZ.
Let spec_add2: forall x y,
[|w_add2 x y|] = w_to_Z x + w_to_Z y.
unfold w_add2.
- intros xh xl; generalize (spec_add_c op_spec xh xl).
- unfold w_add_c; case znz_add_c; unfold interp_carry; simpl ww_to_Z.
+ intros xh xl; generalize (ZnZ.spec_add_c xh xl).
+ unfold w_add_c; case ZnZ.add_c; unfold interp_carry; simpl ww_to_Z.
intros w0 Hw0; simpl; unfold w_to_Z; rewrite Hw0.
- unfold w_0; rewrite spec_0; simpl; auto with zarith.
+ unfold w_0; rewrite ZnZ.spec_0; simpl; auto with zarith.
intros w0; rewrite Zmult_1_l; simpl.
- unfold w_to_Z, w_1; rewrite spec_1; auto with zarith.
+ unfold w_to_Z, w_1; rewrite ZnZ.spec_1; auto with zarith.
rewrite Zmult_1_l; auto.
Qed.
Let spec_low: forall x,
w_to_Z (low x) = [|x|] mod wB.
intros x; case x; simpl low.
- unfold ww_to_Z, w_to_Z, w_0; rewrite (spec_0 op_spec); simpl.
- rewrite Zmod_small; auto with zarith.
- split; auto with zarith.
- unfold wB, base; auto with zarith.
+ unfold ww_to_Z, w_to_Z, w_0; rewrite ZnZ.spec_0; simpl; auto.
intros xh xl; simpl.
rewrite Zplus_comm; rewrite Z_mod_plus; auto with zarith.
rewrite Zmod_small; auto with zarith.
@@ -608,7 +596,7 @@ Section Z_2nZ.
unfold w_to_Z, _ww_zdigits.
rewrite spec_add2.
unfold w_to_Z, w_zdigits, w_digits.
- rewrite spec_zdigits; auto.
+ rewrite ZnZ.spec_zdigits; auto.
rewrite Zpos_xO; auto with zarith.
Qed.
@@ -618,9 +606,8 @@ Section Z_2nZ.
refine (spec_ww_head00 w_0 w_0W
w_compare w_head0 w_add2 w_zdigits _ww_zdigits
w_to_Z _ _ _ (refl_equal _ww_digits) _ _ _ _); auto.
- exact (spec_compare op_spec).
- exact (spec_head00 op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_head00.
+ exact ZnZ.spec_zdigits.
Qed.
Let spec_ww_head0 : forall x, 0 < [|x|] ->
@@ -629,8 +616,7 @@ Section Z_2nZ.
refine (spec_ww_head0 w_0 w_0W w_compare w_head0
w_add2 w_zdigits _ww_zdigits
w_to_Z _ _ _ _ _ _ _);wwauto.
- exact (spec_compare op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_zdigits.
Qed.
Let spec_ww_tail00 : forall x, [|x|] = 0 -> [|tail0 x|] = Zpos _ww_digits.
@@ -638,9 +624,8 @@ Section Z_2nZ.
refine (spec_ww_tail00 w_0 w_0W
w_compare w_tail0 w_add2 w_zdigits _ww_zdigits
w_to_Z _ _ _ (refl_equal _ww_digits) _ _ _ _); wwauto.
- exact (spec_compare op_spec).
- exact (spec_tail00 op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_tail00.
+ exact ZnZ.spec_zdigits.
Qed.
@@ -649,8 +634,7 @@ Section Z_2nZ.
Proof.
refine (spec_ww_tail0 (w_digits := w_digits) w_0 w_0W w_compare w_tail0
w_add2 w_zdigits _ww_zdigits w_to_Z _ _ _ _ _ _ _);wwauto.
- exact (spec_compare op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_zdigits.
Qed.
Lemma spec_ww_add_mul_div : forall x y p,
@@ -659,10 +643,10 @@ Section Z_2nZ.
([|x|] * (2 ^ [|p|]) +
[|y|] / (2 ^ ((Zpos _ww_digits) - [|p|]))) mod wwB.
Proof.
- refine (@spec_ww_add_mul_div w w_0 w_WW w_W0 w_0W compare w_add_mul_div
+ refine (@spec_ww_add_mul_div t w_0 w_WW w_W0 w_0W compare w_add_mul_div
sub w_digits w_zdigits low w_to_Z
_ _ _ _ _ _ _ _ _ _ _);wwauto.
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_zdigits.
Qed.
Let spec_ww_div_gt : forall a b,
@@ -671,29 +655,29 @@ Section Z_2nZ.
[|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
+(@spec_ww_div_gt t 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_zdigits ww_1 add_mul_div w_zdigits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
).
- exact (spec_0 op_spec).
- exact (spec_to_Z op_spec).
+ exact ZnZ.spec_0.
+ exact ZnZ.spec_to_Z.
wwauto.
wwauto.
- exact (spec_compare op_spec).
- exact (spec_eq0 op_spec).
- exact (spec_opp_c op_spec).
- exact (spec_opp op_spec).
- exact (spec_opp_carry op_spec).
- exact (spec_sub_c op_spec).
- exact (spec_sub op_spec).
- exact (spec_sub_carry op_spec).
- exact (spec_div_gt op_spec).
- exact (spec_add_mul_div op_spec).
- exact (spec_head0 op_spec).
- exact (spec_div21 op_spec).
+ exact ZnZ.spec_compare.
+ exact ZnZ.spec_eq0.
+ exact ZnZ.spec_opp_c.
+ exact ZnZ.spec_opp.
+ exact ZnZ.spec_opp_carry.
+ exact ZnZ.spec_sub_c.
+ exact ZnZ.spec_sub.
+ exact ZnZ.spec_sub_carry.
+ exact ZnZ.spec_div_gt.
+ exact ZnZ.spec_add_mul_div.
+ exact ZnZ.spec_head0.
+ exact ZnZ.spec_div21.
exact spec_w_div32.
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_zdigits.
exact spec_ww_digits.
exact spec_ww_1.
exact spec_ww_add_mul_div.
@@ -711,15 +695,14 @@ refine
[|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
+ refine (@spec_ww_mod_gt t 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_zdigits ww_1 add_mul_div
w_zdigits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);wwauto.
- exact (spec_compare op_spec).
- exact (spec_div_gt op_spec).
- exact (spec_div21 op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_div_gt.
+ exact ZnZ.spec_div21.
+ exact ZnZ.spec_zdigits.
exact spec_ww_add_mul_div.
Qed.
@@ -731,37 +714,33 @@ refine
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 _
+ refine (@spec_ww_gcd_gt t 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_0W w_compare w_opp_c w_opp
+ refine (@spec_ww_gcd_gt_aux t w_digits w_0 w_WW w_0W 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_zdigits ww_1 add_mul_div w_zdigits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);wwauto.
- exact (spec_compare op_spec).
- exact (spec_div21 op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_div21.
+ exact ZnZ.spec_zdigits.
exact spec_ww_add_mul_div.
- refine (@spec_gcd_cont w w_digits ww_1 w_to_Z _ _ w_0 w_1 w_compare
+ refine (@spec_gcd_cont t 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
+ refine (@spec_ww_gcd t 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_0W w_compare w_opp_c w_opp
+ refine (@spec_ww_gcd_gt_aux t w_digits w_0 w_WW w_0W 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_zdigits ww_1 add_mul_div w_zdigits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _);wwauto.
- exact (spec_compare op_spec).
- exact (spec_div21 op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_div21.
+ exact ZnZ.spec_zdigits.
exact spec_ww_add_mul_div.
- refine (@spec_gcd_cont w w_digits ww_1 w_to_Z _ _ w_0 w_1 w_compare
+ refine (@spec_gcd_cont t 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,
@@ -770,8 +749,8 @@ refine
| 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).
+ refine (@spec_ww_is_even t w_is_even w_0 w_1 w_Bm1 w_digits _ _ _ _ _); auto.
+ exact ZnZ.spec_is_even.
Qed.
Let spec_ww_sqrt2 : forall x y,
@@ -781,60 +760,57 @@ refine
[+|r|] <= 2 * [|s|].
Proof.
intros x y H.
- refine (@spec_ww_sqrt2 w w_is_even w_compare w_0 w_1 w_Bm1
+ refine (@spec_ww_sqrt2 t w_is_even w_compare w_0 w_1 w_Bm1
w_0W w_sub w_square_c w_div21 w_add_mul_div w_digits w_zdigits
_ww_zdigits
w_add_c w_sqrt2 w_pred pred_c pred add_c add sub_c add_mul_div
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _); wwauto.
- exact (spec_zdigits op_spec).
- exact (spec_more_than_1_digit op_spec).
- exact (spec_is_even op_spec).
- exact (spec_compare op_spec).
- exact (spec_div21 op_spec).
- exact (spec_ww_add_mul_div).
- exact (spec_sqrt2 op_spec).
+ exact ZnZ.spec_zdigits.
+ exact ZnZ.spec_more_than_1_digit.
+ exact ZnZ.spec_is_even.
+ exact ZnZ.spec_div21.
+ exact spec_ww_add_mul_div.
+ exact ZnZ.spec_sqrt2.
Qed.
Let spec_ww_sqrt : forall x,
[|sqrt x|] ^ 2 <= [|x|] < ([|sqrt x|] + 1) ^ 2.
Proof.
- refine (@spec_ww_sqrt w w_is_even w_0 w_1 w_Bm1
+ refine (@spec_ww_sqrt t w_is_even w_0 w_1 w_Bm1
w_sub w_add_mul_div w_digits w_zdigits _ww_zdigits
w_sqrt2 pred add_mul_div head0 compare
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _); wwauto.
- exact (spec_zdigits op_spec).
- exact (spec_more_than_1_digit op_spec).
- exact (spec_is_even op_spec).
- exact (spec_ww_add_mul_div).
- exact (spec_sqrt2 op_spec).
+ exact ZnZ.spec_zdigits.
+ exact ZnZ.spec_more_than_1_digit.
+ exact ZnZ.spec_is_even.
+ exact spec_ww_add_mul_div.
+ exact ZnZ.spec_sqrt2.
Qed.
- Lemma mk_znz2_spec : znz_spec mk_zn2z_op.
+ Global Instance mk_zn2z_specs : ZnZ.Specs mk_zn2z_ops.
Proof.
- apply mk_znz_spec;auto.
+ apply ZnZ.MkSpecs; auto.
exact spec_ww_add_mul_div.
- refine (@spec_ww_pos_mod w w_0 w_digits w_zdigits w_WW
+ refine (@spec_ww_pos_mod t w_0 w_digits w_zdigits w_WW
w_pos_mod compare w_0W low sub _ww_zdigits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _);wwauto.
- exact (spec_pos_mod op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_zdigits.
unfold w_to_Z, w_zdigits.
- rewrite (spec_zdigits op_spec).
+ rewrite ZnZ.spec_zdigits.
rewrite <- Zpos_xO; exact spec_ww_digits.
Qed.
- Lemma mk_znz2_karatsuba_spec : znz_spec mk_zn2z_op_karatsuba.
+ Global Instance mk_zn2z_specs_karatsuba : ZnZ.Specs mk_zn2z_ops_karatsuba.
Proof.
- apply mk_znz_spec;auto.
+ apply ZnZ.MkSpecs; auto.
exact spec_ww_add_mul_div.
- refine (@spec_ww_pos_mod w w_0 w_digits w_zdigits w_WW
+ refine (@spec_ww_pos_mod t w_0 w_digits w_zdigits w_WW
w_pos_mod compare w_0W low sub _ww_zdigits w_to_Z
_ _ _ _ _ _ _ _ _ _ _ _);wwauto.
- exact (spec_pos_mod op_spec).
- exact (spec_zdigits op_spec).
+ exact ZnZ.spec_zdigits.
unfold w_to_Z, w_zdigits.
- rewrite (spec_zdigits op_spec).
+ rewrite ZnZ.spec_zdigits.
rewrite <- Zpos_xO; exact spec_ww_digits.
Qed.
@@ -842,17 +818,14 @@ End Z_2nZ.
Section MulAdd.
- Variable w: Type.
- Variable op: znz_op w.
- Variable sop: znz_spec op.
+ Context {t : Type}{ops : ZnZ.Ops t}{specs : ZnZ.Specs ops}.
- Definition mul_add:= w_mul_add (znz_0 op) (znz_succ op) (znz_add_c op) (znz_mul_c op).
+ Definition mul_add:= w_mul_add ZnZ.zero ZnZ.succ ZnZ.add_c ZnZ.mul_c.
- Notation "[| x |]" := (znz_to_Z op x) (at level 0, x at level 99).
+ Notation "[| x |]" := (ZnZ.to_Z x) (at level 0, x at level 99).
Notation "[|| x ||]" :=
- (zn2z_to_Z (base (znz_digits op)) (znz_to_Z op) x) (at level 0, x at level 99).
-
+ (zn2z_to_Z (base ZnZ.digits) ZnZ.to_Z x) (at level 0, x at level 99).
Lemma spec_mul_add: forall x y z,
let (zh, zl) := mul_add x y z in
@@ -860,11 +833,11 @@ Section MulAdd.
Proof.
intros x y z.
refine (spec_w_mul_add _ _ _ _ _ _ _ _ _ _ _ _ x y z); auto.
- exact (spec_0 sop).
- exact (spec_to_Z sop).
- exact (spec_succ sop).
- exact (spec_add_c sop).
- exact (spec_mul_c sop).
+ exact ZnZ.spec_0.
+ exact ZnZ.spec_to_Z.
+ exact ZnZ.spec_succ.
+ exact ZnZ.spec_add_c.
+ exact ZnZ.spec_mul_c.
Qed.
End MulAdd.
@@ -873,13 +846,13 @@ End MulAdd.
(** Modular versions of DoubleCyclic *)
Module DoubleCyclic (C:CyclicType) <: CyclicType.
- Definition w := zn2z C.w.
- Definition w_op := mk_zn2z_op C.w_op.
- Definition w_spec := mk_znz2_spec C.w_spec.
+ Definition t := zn2z C.t.
+ Instance ops : ZnZ.Ops t := mk_zn2z_ops.
+ Instance specs : ZnZ.Specs ops := mk_zn2z_specs.
End DoubleCyclic.
Module DoubleCyclicKaratsuba (C:CyclicType) <: CyclicType.
- Definition w := zn2z C.w.
- Definition w_op := mk_zn2z_op_karatsuba C.w_op.
- Definition w_spec := mk_znz2_karatsuba_spec C.w_spec.
+ Definition t := zn2z C.t.
+ Definition ops : ZnZ.Ops t := mk_zn2z_ops_karatsuba.
+ Definition specs : ZnZ.Specs ops := mk_zn2z_specs_karatsuba.
End DoubleCyclicKaratsuba.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleDiv.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleDiv.v
index 4e6eccea..0cb6848e 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleDiv.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleDiv.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleDiv.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
@@ -82,11 +80,7 @@ Section POS_MOD.
Variable spec_w_0W : forall l, [[w_0W l]] = [|l|].
Variable spec_ww_compare : forall x y,
- match ww_compare x y with
- | Eq => [[x]] = [[y]]
- | Lt => [[x]] < [[y]]
- | Gt => [[x]] > [[y]]
- end.
+ ww_compare x y = Zcompare [[x]] [[y]].
Variable spec_ww_sub: forall x y,
[[ww_sub x y]] = ([[x]] - [[y]]) mod wwB.
@@ -105,8 +99,8 @@ Section POS_MOD.
intros w1 p; case (spec_to_w_Z p); intros HH1 HH2.
unfold ww_pos_mod; case w1.
simpl; rewrite Zmod_small; split; auto with zarith.
- intros xh xl; generalize (spec_ww_compare p (w_0W w_zdigits));
- case ww_compare;
+ intros xh xl; rewrite spec_ww_compare.
+ case Zcompare_spec;
rewrite spec_w_0W; rewrite spec_zdigits; fold wB;
intros H1.
rewrite H1; simpl ww_to_Z.
@@ -134,8 +128,8 @@ Section POS_MOD.
rewrite Z_mod_mult; auto with zarith.
autorewrite with w_rewrite rm10.
rewrite Zmod_mod; auto with zarith.
-generalize (spec_ww_compare p ww_zdigits);
- case ww_compare; rewrite spec_ww_zdigits;
+ rewrite spec_ww_compare.
+ case Zcompare_spec; rewrite spec_ww_zdigits;
rewrite spec_zdigits; intros H2.
replace (2^[[p]]) with wwB.
rewrite Zmod_small; auto with zarith.
@@ -266,12 +260,7 @@ Section DoubleDiv32.
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.
+ forall x y, w_compare x y = Zcompare [|x|] [|y|].
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.
@@ -343,7 +332,7 @@ Section DoubleDiv32.
(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).
+ rewrite spec_compare. case Zcompare_spec; intro Hcmp.
simpl in Hlt.
rewrite Hcmp in Hlt;assert ([|a2|] < [|b2|]). omega.
assert ([[WW (w_sub a2 b2) a3]] = ([|a2|]-[|b2|])*wB + [|a3|] + wwB).
@@ -545,11 +534,7 @@ Section DoubleDiv21.
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.
+ ww_compare x y = Zcompare [[x]] [[y]].
Variable spec_ww_sub : forall x y, [[ww_sub x y]] = ([[x]] - [[y]]) mod wwB.
Theorem wwB_div: wwB = 2 * (wwB / 2).
@@ -576,10 +561,9 @@ Section DoubleDiv21.
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.
+ intros H1 H2;simpl in H1;Spec_ww_to_Z a2.
+ rewrite spec_ww_compare. case Zcompare_spec;
+ simpl;try rewrite spec_ww_1;autorewrite with rm10; intros;zarith.
rewrite spec_ww_sub;simpl. rewrite Zmod_small;zarith.
split. ring.
assert (wwB <= 2*[[b]]);zarith.
@@ -809,12 +793,7 @@ Section DoubleDivGt.
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.
+ forall x y, w_compare x y = Zcompare [|x|] [|y|].
Variable spec_eq0 : forall x, w_eq0 x = true -> [|x|] = 0.
Variable spec_opp_c : forall x, [-|w_opp_c x|] = -[|x|].
@@ -914,7 +893,7 @@ Section DoubleDivGt.
end in [[WW ah al]]=[[q]]*[[WW bh bl]]+[[r]] /\ 0 <=[[r]]< [[WW bh bl]]).
assert (Hh := spec_head0 Hpos).
lazy zeta.
- generalize (spec_compare (w_head0 bh) w_0); case w_compare;
+ rewrite spec_compare; case Zcompare_spec;
rewrite spec_w_0; intros HH.
generalize Hh; rewrite HH; simpl Zpower;
rewrite Zmult_1_l; intros (HH1, HH2); clear HH.
@@ -1058,14 +1037,13 @@ Section DoubleDivGt.
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_compare; case Zcompare_spec; intros Hcmp.
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_double_divn1 w w_digits w_zdigits w_0 w_WW w_head0 w_add_mul_div
w_div21 w_compare w_sub w_to_Z spec_to_Z spec_w_zdigits spec_w_0 spec_w_WW spec_head0
spec_add_mul_div spec_div21 spec_compare spec_sub 1 (WW ah al) bl Hpos).
- unfold double_to_Z,double_wB,double_digits in H2.
destruct (double_divn1 w_zdigits w_0 w_WW w_head0 w_add_mul_div w_div21
w_compare w_sub 1
(WW ah al) bl).
@@ -1154,7 +1132,7 @@ Section DoubleDivGt.
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_compare; case Zcompare_spec; intros H2.
rewrite (@spec_double_modn1_aux w w_zdigits w_0 w_WW w_head0 w_add_mul_div
w_div21 w_compare w_sub w_to_Z spec_w_0 spec_compare 1 (WW ah al) bl).
destruct (double_divn1 w_zdigits w_0 w_WW w_head0 w_add_mul_div w_div21 w_compare w_sub 1
@@ -1227,13 +1205,14 @@ Section DoubleDivGt.
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 spec_compare, spec_w_0.
+ case Zcompare_spec; intros Hbh.
+ simpl ww_to_Z in *. 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.
+ rewrite spec_compare, spec_w_0.
+ case Zcompare_spec; intros 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 (double_to_Z w_digits w_to_Z 1 (WW ah al)).
rewrite <- (@spec_double_modn1 w w_digits w_zdigits w_0 w_WW w_head0 w_add_mul_div
@@ -1243,20 +1222,20 @@ Section DoubleDivGt.
rewrite (@spec_double_modn1 w w_digits w_zdigits w_0 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;exfalso;omega.
- rewrite spec_w_0 in Hbh;assert (H:= spec_ww_mod_gt_aux _ _ _ Hgt Hbh).
+ Spec_w_to_Z bl;exfalso;omega.
+ 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.
+ rewrite spec_compare, spec_w_0; case Zcompare_spec; intros Hmh.
+ simpl;rewrite <- Hmh;simpl.
+ rewrite spec_compare, spec_w_0; case Zcompare_spec; intros Hml.
+ rewrite <- Hml;simpl;apply Zis_gcd_0.
+ simpl; rewrite spec_w_0; simpl.
+ apply Zis_gcd_mod;zarith.
change ([|bh|] * wB + [|bl|]) with (double_to_Z w_digits w_to_Z 1 (WW bh bl)).
rewrite <- (@spec_double_modn1 w w_digits w_zdigits w_0 w_WW w_head0 w_add_mul_div
w_div21 w_compare w_sub w_to_Z spec_to_Z spec_w_zdigits spec_w_0 spec_w_WW spec_head0 spec_add_mul_div
@@ -1265,8 +1244,8 @@ Section DoubleDivGt.
rewrite (@spec_double_modn1 w w_digits w_zdigits w_0 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;exfalso;omega.
- rewrite spec_w_0 in Hmh. assert ([[WW bh bl]] > [[WW mh ml]]).
+ Spec_w_to_Z ml;exfalso;omega.
+ 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).
@@ -1300,8 +1279,8 @@ Section DoubleDivGt.
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;exfalso;zarith.
- rewrite spec_w_0 in Hbh;Spec_w_to_Z bh;exfalso;zarith.
+ Spec_w_to_Z mh;exfalso;zarith.
+ Spec_w_to_Z bh;exfalso;zarith.
Qed.
Lemma spec_ww_gcd_gt_aux :
@@ -1374,11 +1353,7 @@ Section DoubleDiv.
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.
+ ww_compare x y = Zcompare [[x]] [[y]].
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]] /\
@@ -1400,20 +1375,20 @@ Section DoubleDiv.
0 <= [[r]] < [[b]].
Proof.
intros a b Hpos;unfold ww_div.
- assert (H:=spec_ww_compare a b);destruct (ww_compare a b).
+ rewrite spec_ww_compare; case Zcompare_spec; intros.
simpl;rewrite spec_ww_1;split;zarith.
simpl;split;[ring|Spec_ww_to_Z a;zarith].
- apply spec_ww_div_gt;trivial.
+ apply spec_ww_div_gt;auto with zarith.
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).
+ rewrite spec_ww_compare; case Zcompare_spec; intros.
simpl;apply Zmod_unique with 1;try rewrite H;zarith.
Spec_ww_to_Z a;symmetry;apply Zmod_small;zarith.
- apply spec_ww_mod_gt;trivial.
+ apply spec_ww_mod_gt;auto with zarith.
Qed.
@@ -1431,12 +1406,7 @@ Section DoubleDiv.
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.
+ forall x y, w_compare x y = Zcompare [|x|] [|y|].
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|].
@@ -1468,14 +1438,14 @@ Section DoubleDiv.
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).
+ unfold gcd_cont; rewrite spec_compare, spec_w_1.
+ case Zcompare_spec; intros Hcmpy.
+ simpl;rewrite H;simpl;
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; exfalso;zarith.
- assert ([|yl|] = 0). Spec_w_to_Z yl;zarith.
- rewrite H0;simpl;apply Zis_gcd_0;trivial.
+ assert (H0 : [|yl|] = 0) by (Spec_w_to_Z yl;zarith).
+ simpl. rewrite H0, H;simpl;apply Zis_gcd_0;trivial.
Qed.
@@ -1528,7 +1498,7 @@ Section DoubleDiv.
| Eq => a
| Lt => ww_gcd_gt b a
end).
- assert (Hcmp := spec_ww_compare a b);destruct (ww_compare a b).
+ rewrite spec_ww_compare; case Zcompare_spec; intros Hcmp.
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.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleDivn1.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleDivn1.v
index 4bdb75d6..062282f2 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleDivn1.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleDivn1.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,17 +8,17 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleDivn1.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
-Require Import ZArith.
+Require Import ZArith Ndigits.
Require Import BigNumPrelude.
Require Import DoubleType.
Require Import DoubleBase.
Local Open Scope Z_scope.
+Local Infix "<<" := Pos.shiftl_nat (at level 30).
+
Section GENDIVN1.
Variable w : Type.
@@ -62,12 +62,7 @@ Section GENDIVN1.
[|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
0 <= [|r|] < [|b|].
Variable spec_compare :
- forall x y,
- match w_compare x y with
- | Eq => [|x|] = [|y|]
- | Lt => [|x|] < [|y|]
- | Gt => [|x|] > [|y|]
- end.
+ forall x y, w_compare x y = Zcompare [|x|] [|y|].
Variable spec_sub: forall x y,
[|w_sub x y|] = ([|x|] - [|y|]) mod wB.
@@ -162,14 +157,10 @@ Section GENDIVN1.
| S n => double_divn1_p_aux n (double_divn1_p n)
end.
- Lemma p_lt_double_digits : forall n, [|p|] <= Zpos (double_digits w_digits n).
+ Lemma p_lt_double_digits : forall n, [|p|] <= Zpos (w_digits << n).
Proof.
-(*
- induction n;simpl. destruct p_bounded;trivial.
- case (spec_to_Z p); rewrite Zpos_xO;auto with zarith.
-*)
induction n;simpl. trivial.
- case (spec_to_Z p); rewrite Zpos_xO;auto with zarith.
+ case (spec_to_Z p); rewrite Pshiftl_nat_S, Zpos_xO;auto with zarith.
Qed.
Lemma spec_double_divn1_p : forall n r h l,
@@ -177,14 +168,14 @@ Section GENDIVN1.
let (q,r') := double_divn1_p n r h l in
[|r|] * double_wB w_digits n +
([!n|h!]*2^[|p|] +
- [!n|l!] / (2^(Zpos(double_digits w_digits n) - [|p|])))
+ [!n|l!] / (2^(Zpos(w_digits << n) - [|p|])))
mod double_wB w_digits n = [!n|q!] * [|b2p|] + [|r'|] /\
0 <= [|r'|] < [|b2p|].
Proof.
case (spec_to_Z p); intros HH0 HH1.
induction n;intros.
simpl (double_divn1_p 0 r h l).
- unfold double_to_Z, double_wB, double_digits.
+ unfold double_to_Z, double_wB, "<<".
rewrite <- spec_add_mul_divp.
exact (spec_div21 (w_add_mul_div p h l) b2p_le H).
simpl (double_divn1_p (S n) r h l).
@@ -196,24 +187,24 @@ Section GENDIVN1.
replace ([|r|] * (double_wB w_digits n * double_wB w_digits n) +
(([!n|hh!] * double_wB w_digits n + [!n|hl!]) * 2 ^ [|p|] +
([!n|lh!] * double_wB w_digits n + [!n|ll!]) /
- 2^(Zpos (double_digits w_digits (S n)) - [|p|])) mod
+ 2^(Zpos (w_digits << (S n)) - [|p|])) mod
(double_wB w_digits n * double_wB w_digits n)) with
(([|r|] * double_wB w_digits n + ([!n|hh!] * 2^[|p|] +
- [!n|hl!] / 2^(Zpos (double_digits w_digits n) - [|p|])) mod
+ [!n|hl!] / 2^(Zpos (w_digits << n) - [|p|])) mod
double_wB w_digits n) * double_wB w_digits n +
([!n|hl!] * 2^[|p|] +
- [!n|lh!] / 2^(Zpos (double_digits w_digits n) - [|p|])) mod
+ [!n|lh!] / 2^(Zpos (w_digits << n) - [|p|])) mod
double_wB w_digits n).
generalize (IHn r hh hl H);destruct (double_divn1_p n r hh hl) as (qh,rh);
intros (H3,H4);rewrite H3.
assert ([|rh|] < [|b2p|]). omega.
replace (([!n|qh!] * [|b2p|] + [|rh|]) * double_wB w_digits n +
([!n|hl!] * 2 ^ [|p|] +
- [!n|lh!] / 2 ^ (Zpos (double_digits w_digits n) - [|p|])) mod
+ [!n|lh!] / 2 ^ (Zpos (w_digits << n) - [|p|])) mod
double_wB w_digits n) with
([!n|qh!] * [|b2p|] *double_wB w_digits n + ([|rh|]*double_wB w_digits n +
([!n|hl!] * 2 ^ [|p|] +
- [!n|lh!] / 2 ^ (Zpos (double_digits w_digits n) - [|p|])) mod
+ [!n|lh!] / 2 ^ (Zpos (w_digits << n) - [|p|])) mod
double_wB w_digits n)). 2:ring.
generalize (IHn rh hl lh H0);destruct (double_divn1_p n rh hl lh) as (ql,rl);
intros (H5,H6);rewrite H5.
@@ -229,52 +220,52 @@ Section GENDIVN1.
unfold double_wB,base.
assert (UU:=p_lt_double_digits n).
rewrite Zdiv_shift_r;auto with zarith.
- 2:change (Zpos (double_digits w_digits (S n)))
- with (2*Zpos (double_digits w_digits n));auto with zarith.
- replace (2 ^ (Zpos (double_digits w_digits (S n)) - [|p|])) with
- (2^(Zpos (double_digits w_digits n) - [|p|])*2^Zpos (double_digits w_digits n)).
+ 2:change (Zpos (w_digits << (S n)))
+ with (2*Zpos (w_digits << n));auto with zarith.
+ replace (2 ^ (Zpos (w_digits << (S n)) - [|p|])) with
+ (2^(Zpos (w_digits << n) - [|p|])*2^Zpos (w_digits << n)).
rewrite Zdiv_mult_cancel_r;auto with zarith.
rewrite Zmult_plus_distr_l with (p:= 2^[|p|]).
pattern ([!n|hl!] * 2^[|p|]) at 2;
- rewrite (shift_unshift_mod (Zpos(double_digits w_digits n))([|p|])([!n|hl!]));
+ rewrite (shift_unshift_mod (Zpos(w_digits << n))([|p|])([!n|hl!]));
auto with zarith.
rewrite Zplus_assoc.
replace
- ([!n|hh!] * 2^Zpos (double_digits w_digits n)* 2^[|p|] +
- ([!n|hl!] / 2^(Zpos (double_digits w_digits n)-[|p|])*
- 2^Zpos(double_digits w_digits n)))
+ ([!n|hh!] * 2^Zpos (w_digits << n)* 2^[|p|] +
+ ([!n|hl!] / 2^(Zpos (w_digits << n)-[|p|])*
+ 2^Zpos(w_digits << n)))
with
(([!n|hh!] *2^[|p|] + double_to_Z w_digits w_to_Z n hl /
- 2^(Zpos (double_digits w_digits n)-[|p|]))
- * 2^Zpos(double_digits w_digits n));try (ring;fail).
+ 2^(Zpos (w_digits << n)-[|p|]))
+ * 2^Zpos(w_digits << n));try (ring;fail).
rewrite <- Zplus_assoc.
rewrite <- (Zmod_shift_r ([|p|]));auto with zarith.
replace
- (2 ^ Zpos (double_digits w_digits n) * 2 ^ Zpos (double_digits w_digits n)) with
- (2 ^ (Zpos (double_digits w_digits n) + Zpos (double_digits w_digits n))).
- rewrite (Zmod_shift_r (Zpos (double_digits w_digits n)));auto with zarith.
- replace (2 ^ (Zpos (double_digits w_digits n) + Zpos (double_digits w_digits n)))
- with (2^Zpos(double_digits w_digits n) *2^Zpos(double_digits w_digits n)).
+ (2 ^ Zpos (w_digits << n) * 2 ^ Zpos (w_digits << n)) with
+ (2 ^ (Zpos (w_digits << n) + Zpos (w_digits << n))).
+ rewrite (Zmod_shift_r (Zpos (w_digits << n)));auto with zarith.
+ replace (2 ^ (Zpos (w_digits << n) + Zpos (w_digits << n)))
+ with (2^Zpos(w_digits << n) *2^Zpos(w_digits << n)).
rewrite (Zmult_comm (([!n|hh!] * 2 ^ [|p|] +
- [!n|hl!] / 2 ^ (Zpos (double_digits w_digits n) - [|p|])))).
+ [!n|hl!] / 2 ^ (Zpos (w_digits << n) - [|p|])))).
rewrite Zmult_mod_distr_l;auto with zarith.
ring.
rewrite Zpower_exp;auto with zarith.
- assert (0 < Zpos (double_digits w_digits n)). unfold Zlt;reflexivity.
+ assert (0 < Zpos (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 ([|p|] + (Zpos (double_digits w_digits n) - [|p|])) with
- (Zpos(double_digits w_digits n));auto with zarith.
+ replace ([|p|] + (Zpos (w_digits << n) - [|p|])) with
+ (Zpos(w_digits << n));auto with zarith.
rewrite <- Zpower_exp;auto with zarith.
- replace (Zpos (double_digits w_digits (S n)) - [|p|]) with
- (Zpos (double_digits w_digits n) - [|p|] +
- Zpos (double_digits w_digits n));trivial.
- change (Zpos (double_digits w_digits (S n))) with
- (2*Zpos (double_digits w_digits n)). ring.
+ replace (Zpos (w_digits << (S n)) - [|p|]) with
+ (Zpos (w_digits << n) - [|p|] +
+ Zpos (w_digits << n));trivial.
+ change (Zpos (w_digits << (S n))) with
+ (2*Zpos (w_digits << n)). ring.
Qed.
Definition double_modn1_p_aux n (modn1 : w -> word w n -> word w n -> w) r h l:=
@@ -311,20 +302,21 @@ Section GENDIVN1.
end
end.
- Lemma spec_double_digits:forall n, Zpos w_digits <= Zpos (double_digits w_digits n).
+ Lemma spec_double_digits:forall n, Zpos w_digits <= Zpos (w_digits << n).
Proof.
induction n;simpl;auto with zarith.
- change (Zpos (xO (double_digits w_digits n))) with
- (2*Zpos (double_digits w_digits n)).
- assert (0 < Zpos w_digits);auto with zarith.
- exact (refl_equal Lt).
+ rewrite Pshiftl_nat_S.
+ change (Zpos (xO (w_digits << n))) with
+ (2*Zpos (w_digits << n)).
+ assert (0 < Zpos w_digits) by reflexivity.
+ auto with zarith.
Qed.
Lemma spec_high : forall n (x:word w n),
- [|high n x|] = [!n|x!] / 2^(Zpos (double_digits w_digits n) - Zpos w_digits).
+ [|high n x|] = [!n|x!] / 2^(Zpos (w_digits << n) - Zpos w_digits).
Proof.
induction n;intros.
- unfold high,double_digits,double_to_Z.
+ unfold high,double_to_Z. rewrite Pshiftl_nat_0.
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_double_digits n).
@@ -336,18 +328,18 @@ Section GENDIVN1.
assert (U1 := spec_double_to_Z w_digits w_to_Z spec_to_Z n w1).
simpl [!S n|WW w0 w1!].
unfold double_wB,base;rewrite Zdiv_shift_r;auto with zarith.
- replace (2 ^ (Zpos (double_digits w_digits (S n)) - Zpos w_digits)) with
- (2^(Zpos (double_digits w_digits n) - Zpos w_digits) *
- 2^Zpos (double_digits w_digits n)).
+ replace (2 ^ (Zpos (w_digits << (S n)) - Zpos w_digits)) with
+ (2^(Zpos (w_digits << n) - Zpos w_digits) *
+ 2^Zpos (w_digits << n)).
rewrite Zdiv_mult_cancel_r;auto with zarith.
rewrite <- Zpower_exp;auto with zarith.
- replace (Zpos (double_digits w_digits n) - Zpos w_digits +
- Zpos (double_digits w_digits n)) with
- (Zpos (double_digits w_digits (S n)) - Zpos w_digits);trivial.
- change (Zpos (double_digits w_digits (S n))) with
- (2*Zpos (double_digits w_digits n));ring.
- change (Zpos (double_digits w_digits (S n))) with
- (2*Zpos (double_digits w_digits n)); auto with zarith.
+ replace (Zpos (w_digits << n) - Zpos w_digits +
+ Zpos (w_digits << n)) with
+ (Zpos (w_digits << (S n)) - Zpos w_digits);trivial.
+ change (Zpos (w_digits << (S n))) with
+ (2*Zpos (w_digits << n));ring.
+ change (Zpos (w_digits << (S n))) with
+ (2*Zpos (w_digits << n)); auto with zarith.
Qed.
Definition double_divn1 (n:nat) (a:word w n) (b:w) :=
@@ -373,7 +365,7 @@ Section GENDIVN1.
intros n a b H. unfold double_divn1.
case (spec_head0 H); intros H0 H1.
case (spec_to_Z (w_head0 b)); intros HH1 HH2.
- generalize (spec_compare (w_head0 b) w_0); case w_compare;
+ rewrite spec_compare; case Zcompare_spec;
rewrite spec_0; intros H2; auto with zarith.
assert (Hv1: wB/2 <= [|b|]).
generalize H0; rewrite H2; rewrite Zpower_0_r;
@@ -432,13 +424,13 @@ Section GENDIVN1.
rewrite spec_add_mul_div in H7;auto with zarith.
rewrite spec_0 in H7;rewrite Zmult_0_l in H7;rewrite Zplus_0_l in H7.
assert (([|high n a|] / 2 ^ (Zpos w_digits - [|w_head0 b|])) mod wB
- = [!n|a!] / 2^(Zpos (double_digits w_digits n) - [|w_head0 b|])).
+ = [!n|a!] / 2^(Zpos (w_digits << n) - [|w_head0 b|])).
rewrite Zmod_small;auto with zarith.
rewrite spec_high. rewrite Zdiv_Zdiv;auto with zarith.
rewrite <- Zpower_exp;auto with zarith.
- replace (Zpos (double_digits w_digits n) - Zpos w_digits +
+ replace (Zpos (w_digits << n) - Zpos w_digits +
(Zpos w_digits - [|w_head0 b|]))
- with (Zpos (double_digits w_digits n) - [|w_head0 b|]);trivial;ring.
+ with (Zpos (w_digits << n) - [|w_head0 b|]);trivial;ring.
assert (H8 := Zpower_gt_0 2 (Zpos w_digits - [|w_head0 b|]));auto with zarith.
split;auto with zarith.
apply Zle_lt_trans with ([|high n a|]);auto with zarith.
@@ -506,7 +498,7 @@ Section GENDIVN1.
double_modn1 n a b = snd (double_divn1 n a b).
Proof.
intros n a b;unfold double_divn1,double_modn1.
- generalize (spec_compare (w_head0 b) w_0); case w_compare;
+ rewrite spec_compare; case Zcompare_spec;
rewrite spec_0; intros H2; auto with zarith.
apply spec_double_modn1_0.
apply spec_double_modn1_0.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleLift.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleLift.v
index 36e3da9b..a6a0fc8e 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleLift.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleLift.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleLift.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
@@ -106,17 +104,9 @@ Section DoubleLift.
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.
+ w_compare x y = Zcompare [|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.
+ ww_compare x y = Zcompare [[x]] [[y]].
Variable spec_ww_digits : ww_Digits = xO w_digits.
Variable spec_w_head00 : forall x, [|x|] = 0 -> [|w_head0 x|] = Zpos w_digits.
Variable spec_w_head0 : forall x, 0 < [|x|] ->
@@ -159,7 +149,7 @@ Section DoubleLift.
absurd (0 < [|xh|] * wB + [|xl|]); auto with zarith.
rewrite <- Hy3; rewrite Zplus_0_r; auto with zarith.
apply Zmult_lt_0_compat; auto with zarith.
- generalize (spec_compare w_0 xh); case w_compare.
+ rewrite spec_compare. case Zcompare_spec.
intros H; simpl.
rewrite spec_w_add; rewrite spec_w_head00.
rewrite spec_zdigits; rewrite spec_ww_digits.
@@ -176,9 +166,8 @@ Section DoubleLift.
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.
- destruct (w_compare w_0 xh).
- rewrite <- H0. simpl Zplus. rewrite <- H0 in H;simpl in H.
+ rewrite spec_compare, spec_w_0. case Zcompare_spec; intros H0.
+ rewrite <- H0 in *. simpl Zplus. simpl in H.
case (spec_to_Z w_zdigits);
case (spec_to_Z (w_head0 xl)); intros HH1 HH2 HH3 HH4.
rewrite spec_w_add.
@@ -233,7 +222,7 @@ Section DoubleLift.
apply Zmult_lt_0_compat; auto with zarith.
assert (F2: [|xl|] = 0).
rewrite F1 in Hx; auto with zarith.
- generalize (spec_compare w_0 xl); case w_compare.
+ rewrite spec_compare; case Zcompare_spec.
intros H; simpl.
rewrite spec_w_add; rewrite spec_w_tail00; auto.
rewrite spec_zdigits; rewrite spec_ww_digits.
@@ -248,8 +237,7 @@ Section DoubleLift.
clear spec_ww_zdigits.
destruct x as [ |xh xl];simpl ww_to_Z;intros H.
unfold Zlt in H;discriminate H.
- assert (H0 := spec_compare w_0 xl);rewrite spec_w_0 in H0.
- destruct (w_compare w_0 xl).
+ rewrite spec_compare, spec_w_0. case Zcompare_spec; intros H0.
rewrite <- H0; rewrite Zplus_0_r.
case (spec_to_Z (w_tail0 xh)); intros HH1 HH2.
generalize H; rewrite <- H0; rewrite Zplus_0_r; clear H; intros H.
@@ -323,7 +311,7 @@ Section DoubleLift.
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.
- generalize (spec_ww_compare p zdigits); case ww_compare; intros H1.
+ rewrite spec_ww_compare; case Zcompare_spec; intros H1.
rewrite H1; unfold zdigits; rewrite spec_w_0W.
rewrite spec_zdigits; rewrite Zminus_diag; rewrite Zplus_0_r.
simpl ww_to_Z; w_rewrite;zarith.
@@ -365,7 +353,7 @@ Section DoubleLift.
ring_simplify ([[p]] + (Zpos w_digits - [[p]]));fold wB;zarith.
assert (Hv: [[p]] > Zpos w_digits).
generalize H1; clear H1.
- unfold zdigits; rewrite spec_w_0W; rewrite spec_zdigits; auto.
+ unfold zdigits; rewrite spec_w_0W; rewrite spec_zdigits; auto with zarith.
clear H1.
assert (HH0: [|low (ww_sub p zdigits)|] = [[p]] - Zpos w_digits).
rewrite spec_low.
@@ -446,8 +434,7 @@ Section DoubleLift.
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; auto.
- generalize (spec_ww_compare p (w_0W w_zdigits));
- case ww_compare; intros H1; w_rewrite.
+ rewrite spec_ww_compare. case Zcompare_spec; intros H1; w_rewrite.
rewrite (spec_w_add_mul_div w_0 w_0);w_rewrite;zarith.
generalize H1; w_rewrite; rewrite spec_zdigits; clear H1; intros H1.
assert (HH0: [|low p|] = [[p]]).
@@ -464,7 +451,8 @@ Section DoubleLift.
rewrite (spec_w_add_mul_div w_0 w_0);w_rewrite;zarith.
rewrite Zpos_xO in H;zarith.
assert (HH: [|low (ww_sub p (w_0W w_zdigits)) |] = [[p]] - Zpos w_digits).
- generalize H1; clear H1.
+ symmetry in H1; change ([[p]] > [[w_0W w_zdigits]]) in H1.
+ revert H1.
rewrite spec_low.
rewrite spec_ww_sub; w_rewrite; intros H1.
rewrite <- Zmod_div_mod; auto with zarith.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleMul.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleMul.v
index 834e85d2..0032d2c3 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleMul.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleMul.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleMul.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
@@ -248,12 +246,7 @@ Section DoubleMul.
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.
+ forall x y, w_compare x y = Zcompare [|x|] [|y|].
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.
@@ -408,9 +401,9 @@ Section DoubleMul.
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;
+ rewrite spec_w_compare; case Zcompare_spec; 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.
+ rewrite spec_w_compare; case Zcompare_spec; intros Hylh.
rewrite Hylh; rewrite spec_w_0; try (ring; fail).
rewrite spec_w_0; try (ring; fail).
repeat (rewrite spec_ww_sub || rewrite spec_w_sub || rewrite spec_w_mul_c).
@@ -430,7 +423,7 @@ Section DoubleMul.
rewrite spec_w_1; unfold interp_carry in Hz2; rewrite Hz2;
repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
repeat rewrite Zmod_small; auto with zarith; try (ring; fail).
- generalize (spec_w_compare yl yh); case (w_compare yl yh); intros Hylh.
+ rewrite spec_w_compare; case Zcompare_spec; intros Hylh.
rewrite Hylh; 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;
@@ -455,9 +448,9 @@ Section DoubleMul.
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;
+ rewrite spec_w_compare; case Zcompare_spec; 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;
+ rewrite spec_w_compare; case Zcompare_spec; 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;
@@ -480,7 +473,7 @@ Section DoubleMul.
ring.
rewrite Hz2; repeat (rewrite spec_w_sub || rewrite spec_w_mul_c).
repeat rewrite Zmod_small; auto with zarith; try (ring; fail).
- generalize (spec_w_compare yl yh); case (w_compare yl yh); intros Hylh;
+ rewrite spec_w_compare; case Zcompare_spec; 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;
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleSqrt.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleSqrt.v
index 4394178f..b073d6be 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleSqrt.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleSqrt.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleSqrt.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
@@ -220,12 +218,8 @@ Section DoubleSqrt.
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_compare : forall x y,
+ w_compare x y = Zcompare [|x|] [|y|].
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,
@@ -257,11 +251,7 @@ Section DoubleSqrt.
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.
+ ww_compare x y = Zcompare [[x]] [[y]].
Variable spec_ww_head0 : forall x, 0 < [[x]] ->
wwB/ 2 <= 2 ^ [[ww_head0 x]] * [[x]] < wwB.
Variable spec_low: forall x, [|low x|] = [[x]] mod wB.
@@ -299,10 +289,7 @@ intros x; case x; simpl ww_is_even.
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.
+ rewrite !spec_w_compare. repeat case Zcompare_spec.
intros H1 H2; split.
unfold interp_carry; autorewrite with w_rewrite rm10; auto with zarith.
rewrite H1; rewrite H2; ring.
@@ -1108,12 +1095,12 @@ intros x; case x; simpl ww_is_even.
rewrite wwB_wBwB; rewrite Zpower_2.
apply Zmult_le_compat_r; auto with zarith.
case (spec_to_Z w4);auto with zarith.
- Qed.
+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);
+ rewrite spec_ww_compare. case Zcompare_spec;
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.
@@ -1198,7 +1185,7 @@ intros x; case x; simpl ww_is_even.
simpl ww_to_Z; simpl Zpower; unfold Zpower_pos; simpl;
auto with zarith.
intros H1.
- generalize (spec_ww_compare (ww_head1 x) W0); case ww_compare;
+ rewrite spec_ww_compare. case Zcompare_spec;
simpl ww_to_Z; autorewrite with rm10.
generalize H1; case x.
intros HH; contradict HH; simpl ww_to_Z; auto with zarith.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleSub.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleSub.v
index 3167f4c7..e63e20c6 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleSub.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleSub.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleSub.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
diff --git a/theories/Numbers/Cyclic/DoubleCyclic/DoubleType.v b/theories/Numbers/Cyclic/DoubleCyclic/DoubleType.v
index eb1132d4..a274b839 100644
--- a/theories/Numbers/Cyclic/DoubleCyclic/DoubleType.v
+++ b/theories/Numbers/Cyclic/DoubleCyclic/DoubleType.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: DoubleType.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Set Implicit Arguments.
Require Import ZArith.
@@ -55,7 +53,7 @@ Section Zn2Z.
End Zn2Z.
-Implicit Arguments W0 [znz].
+Arguments W0 [znz].
(** From a cyclic representation [w], we iterate the [zn2z] construct
[n] times, gaining the type of binary trees of depth at most [n],
diff --git a/theories/Numbers/Cyclic/Int31/Cyclic31.v b/theories/Numbers/Cyclic/Int31/Cyclic31.v
index 36a1157d..2dd1c3ee 100644
--- a/theories/Numbers/Cyclic/Int31/Cyclic31.v
+++ b/theories/Numbers/Cyclic/Int31/Cyclic31.v
@@ -1,13 +1,11 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: Cyclic31.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
(** * Int31 numbers defines indeed a cyclic structure : Z/(2^31)Z *)
(**
@@ -907,9 +905,11 @@ Section Basics.
apply nshiftr_n_0.
Qed.
- Lemma p2ibis_spec : forall n p, n<=size ->
- Zpos p = ((Z_of_N (fst (p2ibis n p)))*2^(Z_of_nat n) +
- phi (snd (p2ibis n p)))%Z.
+ Local Open Scope Z_scope.
+
+ Lemma p2ibis_spec : forall n p, (n<=size)%nat ->
+ Zpos p = (Z_of_N (fst (p2ibis n p)))*2^(Z_of_nat n) +
+ phi (snd (p2ibis n p)).
Proof.
induction n; intros.
simpl; rewrite Pmult_1_r; auto.
@@ -917,7 +917,7 @@ Section Basics.
(rewrite <- Zpower_Zsucc, <- Zpos_P_of_succ_nat;
auto with zarith).
rewrite (Zmult_comm 2).
- assert (n<=size) by omega.
+ assert (n<=size)%nat by omega.
destruct p; simpl; [ | | auto];
specialize (IHn p H0);
generalize (p2ibis_bounded n p);
@@ -973,7 +973,8 @@ Section Basics.
(** Moreover, [p2ibis] is also related with [p2i] and hence with
[positive_to_int31]. *)
- Lemma double_twice_firstl : forall x, firstl x = D0 -> Twon*x = twice x.
+ Lemma double_twice_firstl : forall x, firstl x = D0 ->
+ (Twon*x = twice x)%int31.
Proof.
intros.
unfold mul31.
@@ -981,7 +982,7 @@ Section Basics.
Qed.
Lemma double_twice_plus_one_firstl : forall x, firstl x = D0 ->
- Twon*x+In = twice_plus_one x.
+ (Twon*x+In = twice_plus_one x)%int31.
Proof.
intros.
rewrite double_twice_firstl; auto.
@@ -1015,8 +1016,8 @@ Section Basics.
Qed.
Lemma positive_to_int31_spec : forall p,
- Zpos p = ((Z_of_N (fst (positive_to_int31 p)))*2^(Z_of_nat size) +
- phi (snd (positive_to_int31 p)))%Z.
+ Zpos p = (Z_of_N (fst (positive_to_int31 p)))*2^(Z_of_nat size) +
+ phi (snd (positive_to_int31 p)).
Proof.
unfold positive_to_int31.
intros; rewrite p2i_p2ibis; auto.
@@ -1033,7 +1034,7 @@ Section Basics.
intros.
pattern x at 1; rewrite <- (phi_inv_phi x).
rewrite <- phi_inv_double.
- assert (0 <= Zdouble (phi x))%Z.
+ assert (0 <= Zdouble (phi x)).
rewrite Zdouble_mult; generalize (phi_bounded x); omega.
destruct (Zdouble (phi x)).
simpl; auto.
@@ -1047,7 +1048,7 @@ Section Basics.
intros.
pattern x at 1; rewrite <- (phi_inv_phi x).
rewrite <- phi_inv_double_plus_one.
- assert (0 <= Zdouble_plus_one (phi x))%Z.
+ assert (0 <= Zdouble_plus_one (phi x)).
rewrite Zdouble_plus_one_mult; generalize (phi_bounded x); omega.
destruct (Zdouble_plus_one (phi x)).
simpl; auto.
@@ -1061,7 +1062,7 @@ Section Basics.
intros.
pattern x at 1; rewrite <- (phi_inv_phi x).
rewrite <- phi_inv_incr.
- assert (0 <= Zsucc (phi x))%Z.
+ assert (0 <= Zsucc (phi x)).
change (Zsucc (phi x)) with ((phi x)+1)%Z;
generalize (phi_bounded x); omega.
destruct (Zsucc (phi x)).
@@ -1083,7 +1084,7 @@ Section Basics.
rewrite incr_twice, phi_twice_plus_one.
remember (phi (complement_negative p)) as q.
rewrite Zdouble_plus_one_mult.
- replace (2*q+1)%Z with (2*(Zsucc q)-1)%Z by omega.
+ replace (2*q+1) with (2*(Zsucc q)-1) by omega.
rewrite <- Zminus_mod_idemp_l, <- Zmult_mod_idemp_r, IHp.
rewrite Zmult_mod_idemp_r, Zminus_mod_idemp_l; auto with zarith.
@@ -1106,81 +1107,61 @@ Section Basics.
End Basics.
-
-Section Int31_Op.
-
-(** Nullity test *)
-Let w_iszero i := match i ?= 0 with Eq => true | _ => false end.
-
-(** Modulo [2^p] *)
-Let w_pos_mod p i :=
- match compare31 p 31 with
+Instance int31_ops : ZnZ.Ops int31 :=
+{
+ digits := 31%positive; (* number of digits *)
+ zdigits := 31; (* number of digits *)
+ to_Z := phi; (* conversion to Z *)
+ of_pos := positive_to_int31; (* positive -> N*int31 : p => N,i
+ where p = N*2^31+phi i *)
+ head0 := head031; (* number of head 0 *)
+ tail0 := tail031; (* number of tail 0 *)
+ zero := 0;
+ one := 1;
+ minus_one := Tn; (* 2^31 - 1 *)
+ compare := compare31;
+ eq0 := fun i => match i ?= 0 with Eq => true | _ => false end;
+ opp_c := fun i => 0 -c i;
+ opp := opp31;
+ opp_carry := fun i => 0-i-1;
+ succ_c := fun i => i +c 1;
+ add_c := add31c;
+ add_carry_c := add31carryc;
+ succ := fun i => i + 1;
+ add := add31;
+ add_carry := fun i j => i + j + 1;
+ pred_c := fun i => i -c 1;
+ sub_c := sub31c;
+ sub_carry_c := sub31carryc;
+ pred := fun i => i - 1;
+ sub := sub31;
+ sub_carry := fun i j => i - j - 1;
+ mul_c := mul31c;
+ mul := mul31;
+ square_c := fun x => x *c x;
+ div21 := div3121;
+ div_gt := div31; (* this is supposed to be the special case of
+ division a/b where a > b *)
+ div := div31;
+ modulo_gt := fun i j => let (_,r) := i/j in r;
+ modulo := fun i j => let (_,r) := i/j in r;
+ gcd_gt := gcd31;
+ gcd := gcd31;
+ add_mul_div := addmuldiv31;
+ pos_mod := (* modulo 2^p *)
+ fun p i =>
+ match p ?= 31 with
| Lt => addmuldiv31 p 0 (addmuldiv31 (31-p) i 0)
| _ => i
- end.
+ end;
+ is_even :=
+ fun i => let (_,r) := i/2 in
+ match r ?= 0 with Eq => true | _ => false end;
+ sqrt2 := sqrt312;
+ sqrt := sqrt31
+}.
-(** Parity test *)
-Let w_iseven i :=
- let (_,r) := i/2 in
- match r ?= 0 with Eq => true | _ => false end.
-
-Definition int31_op := (mk_znz_op
- 31%positive (* number of digits *)
- 31 (* number of digits *)
- phi (* conversion to Z *)
- positive_to_int31 (* positive -> N*int31 : p => N,i where p = N*2^31+phi i *)
- head031 (* number of head 0 *)
- tail031 (* number of tail 0 *)
- (* Basic constructors *)
- 0
- 1
- Tn (* 2^31 - 1 *)
- (* Comparison *)
- compare31
- w_iszero
- (* Basic arithmetic operations *)
- (fun i => 0 -c i)
- opp31
- (fun i => 0-i-1)
- (fun i => i +c 1)
- add31c
- add31carryc
- (fun i => i + 1)
- add31
- (fun i j => i + j + 1)
- (fun i => i -c 1)
- sub31c
- sub31carryc
- (fun i => i - 1)
- sub31
- (fun i j => i - j - 1)
- mul31c
- mul31
- (fun x => x *c x)
- (* special (euclidian) division operations *)
- div3121
- div31 (* this is supposed to be the special case of division a/b where a > b *)
- div31
- (* euclidian division remainder *)
- (* again special case for a > b *)
- (fun i j => let (_,r) := i/j in r)
- (fun i j => let (_,r) := i/j in r)
- gcd31 (*gcd_gt*)
- gcd31 (*gcd*)
- (* shift operations *)
- addmuldiv31 (*add_mul_div *)
- (* modulo 2^p *)
- w_pos_mod
- (* is i even ? *)
- w_iseven
- (* square root operations *)
- sqrt312 (* sqrt2 *)
- sqrt31 (* sqrt *)
-).
-
-End Int31_Op.
-
-Section Int31_Spec.
+Section Int31_Specs.
Local Open Scope Z_scope.
@@ -1222,22 +1203,14 @@ Section Int31_Spec.
reflexivity.
Qed.
- Lemma spec_Bm1 : [| Tn |] = wB - 1.
+ Lemma spec_m1 : [| Tn |] = wB - 1.
Proof.
reflexivity.
Qed.
Lemma spec_compare : forall x y,
- match (x ?= y)%int31 with
- | Eq => [|x|] = [|y|]
- | Lt => [|x|] < [|y|]
- | Gt => [|x|] > [|y|]
- end.
- Proof.
- clear; unfold compare31; simpl; intros.
- case_eq ([|x|] ?= [|y|]); auto.
- intros; apply Zcompare_Eq_eq; auto.
- Qed.
+ (x ?= y)%int31 = ([|x|] ?= [|y|]).
+ Proof. reflexivity. Qed.
(** Addition *)
@@ -1654,12 +1627,10 @@ Section Int31_Spec.
rewrite Zmult_comm, Z_div_mult; auto with zarith.
Qed.
- Let w_pos_mod := int31_op.(znz_pos_mod).
-
Lemma spec_pos_mod : forall w p,
- [|w_pos_mod p w|] = [|w|] mod (2 ^ [|p|]).
+ [|ZnZ.pos_mod p w|] = [|w|] mod (2 ^ [|p|]).
Proof.
- unfold w_pos_mod, znz_pos_mod, int31_op, compare31.
+ unfold ZnZ.pos_mod, int31_ops, compare31.
change [|31|] with 31%Z.
assert (forall w p, 31<=p -> [|w|] = [|w|] mod 2^p).
intros.
@@ -1721,7 +1692,7 @@ Section Int31_Spec.
unfold head031, recl.
change On with (phi_inv (Z_of_nat (31-size))).
replace (head031_alt size x) with
- (head031_alt size x + (31 - size))%nat by (apply plus_0_r; auto).
+ (head031_alt size x + (31 - size))%nat by auto.
assert (size <= 31)%nat by auto with arith.
revert x H; induction size; intros.
@@ -1829,7 +1800,7 @@ Section Int31_Spec.
unfold tail031, recr.
change On with (phi_inv (Z_of_nat (31-size))).
replace (tail031_alt size x) with
- (tail031_alt size x + (31 - size))%nat by (apply plus_0_r; auto).
+ (tail031_alt size x + (31 - size))%nat by auto.
assert (size <= 31)%nat by auto with arith.
revert x H; induction size; intros.
@@ -2018,8 +1989,8 @@ Section Int31_Spec.
Proof.
assert (Hp2: 0 < [|2|]) by exact (refl_equal Lt).
intros Hi Hj Hij H31 Hrec; rewrite sqrt31_step_def.
- generalize (spec_compare (fst (i/j)%int31) j); case compare31;
- rewrite div31_phi; auto; intros Hc;
+ rewrite spec_compare, div31_phi; auto.
+ case Zcompare_spec; auto; intros Hc;
try (split; auto; apply sqrt_test_true; auto with zarith; fail).
apply Hrec; repeat rewrite div31_phi; auto with zarith.
replace [|(j + fst (i / j)%int31)|] with ([|j|] + [|i|] / [|j|]).
@@ -2072,7 +2043,7 @@ Section Int31_Spec.
[|sqrt31 x|] ^ 2 <= [|x|] < ([|sqrt31 x|] + 1) ^ 2.
Proof.
intros i; unfold sqrt31.
- generalize (spec_compare 1 i); case compare31; change [|1|] with 1;
+ rewrite spec_compare. case Zcompare_spec; change [|1|] with 1;
intros Hi; auto with zarith.
repeat rewrite Zpower_2; auto with zarith.
apply iter31_sqrt_correct; auto with zarith.
@@ -2157,7 +2128,7 @@ Section Int31_Spec.
unfold phi2; apply Zlt_le_trans with ([|ih|] * base)%Z; auto with zarith.
apply Zmult_lt_0_compat; auto with zarith.
apply Zlt_le_trans with (2:= Hih); auto with zarith.
- generalize (spec_compare ih j); case compare31; intros Hc1.
+ rewrite spec_compare. case Zcompare_spec; intros Hc1.
split; auto.
apply sqrt_test_true; auto.
unfold phi2, base; auto with zarith.
@@ -2166,7 +2137,7 @@ Section Int31_Spec.
rewrite Zmult_comm, Z_div_plus_full_l; unfold base; auto with zarith.
unfold Zpower, Zpower_pos in Hj1; simpl in Hj1; auto with zarith.
case (Zle_or_lt (2 ^ 30) [|j|]); intros Hjj.
- generalize (spec_compare (fst (div3121 ih il j)) j); case compare31;
+ rewrite spec_compare; case Zcompare_spec;
rewrite div312_phi; auto; intros Hc;
try (split; auto; apply sqrt_test_true; auto with zarith; fail).
apply Hrec.
@@ -2274,7 +2245,7 @@ Section Int31_Spec.
2: simpl; unfold Zpower_pos; simpl; auto with zarith.
case (phi_bounded ih); case (phi_bounded il); intros H1 H2 H3 H4.
unfold base, Zpower, Zpower_pos in H2,H4; simpl in H2,H4.
- unfold phi2,Zpower, Zpower_pos; simpl iter_pos; auto with zarith.
+ unfold phi2,Zpower, Zpower_pos. simpl Pos.iter; auto with zarith.
case (iter312_sqrt_correct 31 (fun _ _ j => j) ih il Tn); auto with zarith.
change [|Tn|] with 2147483647; auto with zarith.
intros j1 _ HH; contradict HH.
@@ -2300,7 +2271,7 @@ Section Int31_Spec.
generalize (spec_sub_c il il1).
case sub31c; intros il2 Hil2.
simpl interp_carry in Hil2.
- generalize (spec_compare ih ih1); case compare31.
+ rewrite spec_compare; case Zcompare_spec.
unfold interp_carry.
intros H1; split.
rewrite Zpower_2, <- Hihl1.
@@ -2347,7 +2318,7 @@ Section Int31_Spec.
case (phi_bounded ih); intros H1 H2.
generalize Hih; change (2 ^ Z_of_nat size / 4) with 536870912.
split; auto with zarith.
- generalize (spec_compare (ih - 1) ih1); case compare31.
+ rewrite spec_compare; case Zcompare_spec.
rewrite Hsih.
intros H1; split.
rewrite Zpower_2, <- Hihl1.
@@ -2414,15 +2385,13 @@ Section Int31_Spec.
replace [|il|] with (([|il|] - [|il1|]) + [|il1|]); try ring.
rewrite <-Hil2.
change (-1 * 2 ^ Z_of_nat size) with (-base); ring.
- Qed.
+Qed.
(** [iszero] *)
- Let w_eq0 := int31_op.(znz_eq0).
-
- Lemma spec_eq0 : forall x, w_eq0 x = true -> [|x|] = 0.
+ Lemma spec_eq0 : forall x, ZnZ.eq0 x = true -> [|x|] = 0.
Proof.
- clear; unfold w_eq0, znz_eq0; simpl.
+ clear; unfold ZnZ.eq0; simpl.
unfold compare31; simpl; intros.
change [|0|] with 0 in H.
apply Zcompare_Eq_eq.
@@ -2431,12 +2400,10 @@ Section Int31_Spec.
(* Even *)
- Let w_is_even := int31_op.(znz_is_even).
-
Lemma spec_is_even : forall x,
- if w_is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1.
+ if ZnZ.is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1.
Proof.
- unfold w_is_even; simpl; intros.
+ unfold ZnZ.is_even; simpl; intros.
generalize (spec_div x 2).
destruct (x/2)%int31 as (q,r); intros.
unfold compare31.
@@ -2445,77 +2412,60 @@ Section Int31_Spec.
destruct H; auto with zarith.
replace ([|x|] mod 2) with [|r|].
destruct H; auto with zarith.
- case_eq ([|r|] ?= 0)%Z; intros.
- apply Zcompare_Eq_eq; auto.
- change ([|r|] < 0)%Z in H; auto with zarith.
- change ([|r|] > 0)%Z in H; auto with zarith.
+ case Zcompare_spec; auto with zarith.
apply Zmod_unique with [|q|]; auto with zarith.
Qed.
- Definition int31_spec : znz_spec int31_op.
- split.
- exact phi_bounded.
- exact positive_to_int31_spec.
- exact spec_zdigits.
- exact spec_more_than_1_digit.
-
- exact spec_0.
- exact spec_1.
- exact spec_Bm1.
-
- exact spec_compare.
- exact spec_eq0.
-
- exact spec_opp_c.
- exact spec_opp.
- exact spec_opp_carry.
-
- exact spec_succ_c.
- exact spec_add_c.
- exact spec_add_carry_c.
- exact spec_succ.
- exact spec_add.
- exact spec_add_carry.
-
- exact spec_pred_c.
- exact spec_sub_c.
- exact spec_sub_carry_c.
- exact spec_pred.
- exact spec_sub.
- exact spec_sub_carry.
-
- exact spec_mul_c.
- exact spec_mul.
- exact spec_square_c.
-
- exact spec_div21.
- intros; apply spec_div; auto.
- exact spec_div.
-
- intros; unfold int31_op; simpl; apply spec_mod; auto.
- exact spec_mod.
-
- intros; apply spec_gcd; auto.
- exact spec_gcd.
-
- exact spec_head00.
- exact spec_head0.
- exact spec_tail00.
- exact spec_tail0.
-
- exact spec_add_mul_div.
- exact spec_pos_mod.
-
- exact spec_is_even.
- exact spec_sqrt2.
- exact spec_sqrt.
- Qed.
-
-End Int31_Spec.
+ Global Instance int31_specs : ZnZ.Specs int31_ops := {
+ spec_to_Z := phi_bounded;
+ spec_of_pos := positive_to_int31_spec;
+ spec_zdigits := spec_zdigits;
+ spec_more_than_1_digit := spec_more_than_1_digit;
+ spec_0 := spec_0;
+ spec_1 := spec_1;
+ spec_m1 := spec_m1;
+ spec_compare := spec_compare;
+ spec_eq0 := spec_eq0;
+ spec_opp_c := spec_opp_c;
+ spec_opp := spec_opp;
+ spec_opp_carry := spec_opp_carry;
+ spec_succ_c := spec_succ_c;
+ spec_add_c := spec_add_c;
+ spec_add_carry_c := spec_add_carry_c;
+ spec_succ := spec_succ;
+ spec_add := spec_add;
+ spec_add_carry := spec_add_carry;
+ spec_pred_c := spec_pred_c;
+ spec_sub_c := spec_sub_c;
+ spec_sub_carry_c := spec_sub_carry_c;
+ spec_pred := spec_pred;
+ spec_sub := spec_sub;
+ spec_sub_carry := spec_sub_carry;
+ spec_mul_c := spec_mul_c;
+ spec_mul := spec_mul;
+ spec_square_c := spec_square_c;
+ spec_div21 := spec_div21;
+ spec_div_gt := fun a b _ => spec_div a b;
+ spec_div := spec_div;
+ spec_modulo_gt := fun a b _ => spec_mod a b;
+ spec_modulo := spec_mod;
+ spec_gcd_gt := fun a b _ => spec_gcd a b;
+ spec_gcd := spec_gcd;
+ spec_head00 := spec_head00;
+ spec_head0 := spec_head0;
+ spec_tail00 := spec_tail00;
+ spec_tail0 := spec_tail0;
+ spec_add_mul_div := spec_add_mul_div;
+ spec_pos_mod := spec_pos_mod;
+ spec_is_even := spec_is_even;
+ spec_sqrt2 := spec_sqrt2;
+ spec_sqrt := spec_sqrt }.
+
+End Int31_Specs.
Module Int31Cyclic <: CyclicType.
- Definition w := int31.
- Definition w_op := int31_op.
- Definition w_spec := int31_spec.
+ Definition t := int31.
+ Definition ops := int31_ops.
+ Definition specs := int31_specs.
End Int31Cyclic.
diff --git a/theories/Numbers/Cyclic/Int31/Int31.v b/theories/Numbers/Cyclic/Int31/Int31.v
index 5e1cd0e1..20f750f6 100644
--- a/theories/Numbers/Cyclic/Int31/Int31.v
+++ b/theories/Numbers/Cyclic/Int31/Int31.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,15 +8,11 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: Int31.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NaryFunctions.
Require Import Wf_nat.
Require Export ZArith.
Require Export DoubleType.
-Unset Boxed Definitions.
-
(** * 31-bit integers *)
(** This file contains basic definitions of a 31-bit integer
@@ -353,16 +349,16 @@ Register div31 as int31 div in "coq_int31" by True.
Register compare31 as int31 compare in "coq_int31" by True.
Register addmuldiv31 as int31 addmuldiv in "coq_int31" by True.
-Definition gcd31 (i j:int31) :=
- (fix euler (guard:nat) (i j:int31) {struct guard} :=
- match guard with
- | O => In
- | S p => match j ?= On with
- | Eq => i
- | _ => euler p j (let (_, r ) := i/j in r)
- end
- end)
- (2*size)%nat i j.
+Fixpoint euler (guard:nat) (i j:int31) {struct guard} :=
+ match guard with
+ | O => In
+ | S p => match j ?= On with
+ | Eq => i
+ | _ => euler p j (let (_, r ) := i/j in r)
+ end
+ end.
+
+Definition gcd31 (i j:int31) := euler (2*size)%nat i j.
(** Square root functions using newton iteration
we use a very naive upper-bound on the iteration
diff --git a/theories/Numbers/Cyclic/Int31/Ring31.v b/theories/Numbers/Cyclic/Int31/Ring31.v
index 37dc0871..23e8bd33 100644
--- a/theories/Numbers/Cyclic/Int31/Ring31.v
+++ b/theories/Numbers/Cyclic/Int31/Ring31.v
@@ -1,13 +1,11 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: Ring31.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
(** * Int31 numbers defines Z/(2^31)Z, and can hence be equipped
with a ring structure and a ring tactic *)
@@ -83,9 +81,10 @@ Qed.
Lemma eqb31_eq : forall x y, eqb31 x y = true <-> x=y.
Proof.
unfold eqb31. intros x y.
-generalize (Cyclic31.spec_compare x y).
-destruct (x ?= y); intuition; subst; auto with zarith; try discriminate.
-apply Int31_canonic; auto.
+rewrite Cyclic31.spec_compare. case Zcompare_spec.
+intuition. apply Int31_canonic; auto.
+intuition; subst; auto with zarith; try discriminate.
+intuition; subst; auto with zarith; try discriminate.
Qed.
Lemma eqb31_correct : forall x y, eqb31 x y = true -> x=y.
diff --git a/theories/Numbers/Cyclic/ZModulo/ZModulo.v b/theories/Numbers/Cyclic/ZModulo/ZModulo.v
index aef729bf..d039fdcb 100644
--- a/theories/Numbers/Cyclic/ZModulo/ZModulo.v
+++ b/theories/Numbers/Cyclic/ZModulo/ZModulo.v
@@ -1,13 +1,11 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(* $Id: ZModulo.v 14641 2011-11-06 11:59:10Z herbelin $ *)
-
(** * Type [Z] viewed modulo a particular constant corresponds to [Z/nZ]
as defined abstractly in CyclicAxioms. *)
@@ -33,25 +31,23 @@ Section ZModulo.
Definition wB := base digits.
- Definition znz := Z.
- Definition znz_digits := digits.
- Definition znz_zdigits := Zpos digits.
- Definition znz_to_Z x := x mod wB.
+ Definition t := Z.
+ Definition zdigits := Zpos digits.
+ Definition to_Z x := x mod wB.
- Notation "[| x |]" := (znz_to_Z x) (at level 0, x at level 99).
+ Notation "[| x |]" := (to_Z x) (at level 0, x at level 99).
Notation "[+| c |]" :=
- (interp_carry 1 wB znz_to_Z c) (at level 0, x at level 99).
+ (interp_carry 1 wB to_Z c) (at level 0, x at level 99).
Notation "[-| c |]" :=
- (interp_carry (-1) wB znz_to_Z c) (at level 0, x at level 99).
+ (interp_carry (-1) wB to_Z c) (at level 0, x at level 99).
Notation "[|| x ||]" :=
- (zn2z_to_Z wB znz_to_Z x) (at level 0, x at level 99).
+ (zn2z_to_Z wB to_Z x) (at level 0, x at level 99).
Lemma spec_more_than_1_digit: 1 < Zpos digits.
Proof.
- unfold znz_digits.
generalize digits_ne_1; destruct digits; auto.
destruct 1; auto.
Qed.
@@ -65,12 +61,12 @@ Section ZModulo.
Lemma spec_to_Z_1 : forall x, 0 <= [|x|].
Proof.
- unfold znz_to_Z; intros; destruct (Z_mod_lt x wB wB_pos); auto.
+ unfold to_Z; intros; destruct (Z_mod_lt x wB wB_pos); auto.
Qed.
Lemma spec_to_Z_2 : forall x, [|x|] < wB.
Proof.
- unfold znz_to_Z; intros; destruct (Z_mod_lt x wB wB_pos); auto.
+ unfold to_Z; intros; destruct (Z_mod_lt x wB wB_pos); auto.
Qed.
Hint Resolve spec_to_Z_1 spec_to_Z_2.
@@ -79,16 +75,16 @@ Section ZModulo.
auto.
Qed.
- Definition znz_of_pos x :=
+ Definition of_pos x :=
let (q,r) := Zdiv_eucl_POS x wB in (N_of_Z q, r).
Lemma spec_of_pos : forall p,
- Zpos p = (Z_of_N (fst (znz_of_pos p)))*wB + [|(snd (znz_of_pos p))|].
+ Zpos p = (Z_of_N (fst (of_pos p)))*wB + [|(snd (of_pos p))|].
Proof.
- intros; unfold znz_of_pos; simpl.
+ intros; unfold of_pos; simpl.
generalize (Z_div_mod_POS wB wB_pos p).
destruct (Zdiv_eucl_POS p wB); simpl; destruct 1.
- unfold znz_to_Z; rewrite Zmod_small; auto.
+ unfold to_Z; rewrite Zmod_small; auto.
assert (0 <= z).
replace z with (Zpos p / wB) by
(symmetry; apply Zdiv_unique with z0; auto).
@@ -98,37 +94,37 @@ Section ZModulo.
rewrite Zmult_comm; auto.
Qed.
- Lemma spec_zdigits : [|znz_zdigits|] = Zpos znz_digits.
+ Lemma spec_zdigits : [|zdigits|] = Zpos digits.
Proof.
- unfold znz_to_Z, znz_zdigits, znz_digits.
+ unfold to_Z, zdigits.
apply Zmod_small.
unfold wB, base.
split; auto with zarith.
apply Zpower2_lt_lin; auto with zarith.
Qed.
- Definition znz_0 := 0.
- Definition znz_1 := 1.
- Definition znz_Bm1 := wB - 1.
+ Definition zero := 0.
+ Definition one := 1.
+ Definition minus_one := wB - 1.
- Lemma spec_0 : [|znz_0|] = 0.
+ Lemma spec_0 : [|zero|] = 0.
Proof.
- unfold znz_to_Z, znz_0.
+ unfold to_Z, zero.
apply Zmod_small; generalize wB_pos; auto with zarith.
Qed.
- Lemma spec_1 : [|znz_1|] = 1.
+ Lemma spec_1 : [|one|] = 1.
Proof.
- unfold znz_to_Z, znz_1.
+ unfold to_Z, one.
apply Zmod_small; split; auto with zarith.
unfold wB, base.
apply Zlt_trans with (Zpos digits); auto.
apply Zpower2_lt_lin; auto with zarith.
Qed.
- Lemma spec_Bm1 : [|znz_Bm1|] = wB - 1.
+ Lemma spec_Bm1 : [|minus_one|] = wB - 1.
Proof.
- unfold znz_to_Z, znz_Bm1.
+ unfold to_Z, minus_one.
apply Zmod_small; split; auto with zarith.
unfold wB, base.
cut (1 <= 2 ^ Zpos digits); auto with zarith.
@@ -136,54 +132,46 @@ Section ZModulo.
apply Zpower2_le_lin; auto with zarith.
Qed.
- Definition znz_compare x y := Zcompare [|x|] [|y|].
+ Definition compare x y := Zcompare [|x|] [|y|].
Lemma spec_compare : forall x y,
- match znz_compare x y with
- | Eq => [|x|] = [|y|]
- | Lt => [|x|] < [|y|]
- | Gt => [|x|] > [|y|]
- end.
- Proof.
- intros; unfold znz_compare, Zlt, Zgt.
- case_eq (Zcompare [|x|] [|y|]); auto.
- intros; apply Zcompare_Eq_eq; auto.
- Qed.
+ compare x y = Zcompare [|x|] [|y|].
+ Proof. reflexivity. Qed.
- Definition znz_eq0 x :=
+ Definition eq0 x :=
match [|x|] with Z0 => true | _ => false end.
- Lemma spec_eq0 : forall x, znz_eq0 x = true -> [|x|] = 0.
+ Lemma spec_eq0 : forall x, eq0 x = true -> [|x|] = 0.
Proof.
- unfold znz_eq0; intros; now destruct [|x|].
+ unfold eq0; intros; now destruct [|x|].
Qed.
- Definition znz_opp_c x :=
- if znz_eq0 x then C0 0 else C1 (- x).
- Definition znz_opp x := - x.
- Definition znz_opp_carry x := - x - 1.
+ Definition opp_c x :=
+ if eq0 x then C0 0 else C1 (- x).
+ Definition opp x := - x.
+ Definition opp_carry x := - x - 1.
- Lemma spec_opp_c : forall x, [-|znz_opp_c x|] = -[|x|].
+ Lemma spec_opp_c : forall x, [-|opp_c x|] = -[|x|].
Proof.
- intros; unfold znz_opp_c, znz_to_Z; auto.
- case_eq (znz_eq0 x); intros; unfold interp_carry.
+ intros; unfold opp_c, to_Z; auto.
+ case_eq (eq0 x); intros; unfold interp_carry.
fold [|x|]; rewrite (spec_eq0 x H); auto.
assert (x mod wB <> 0).
- unfold znz_eq0, znz_to_Z in H.
+ unfold eq0, to_Z in H.
intro H0; rewrite H0 in H; discriminate.
rewrite Z_mod_nz_opp_full; auto with zarith.
Qed.
- Lemma spec_opp : forall x, [|znz_opp x|] = (-[|x|]) mod wB.
+ Lemma spec_opp : forall x, [|opp x|] = (-[|x|]) mod wB.
Proof.
- intros; unfold znz_opp, znz_to_Z; auto.
+ intros; unfold opp, to_Z; auto.
change ((- x) mod wB = (0 - (x mod wB)) mod wB).
rewrite Zminus_mod_idemp_r; simpl; auto.
Qed.
- Lemma spec_opp_carry : forall x, [|znz_opp_carry x|] = wB - [|x|] - 1.
+ Lemma spec_opp_carry : forall x, [|opp_carry x|] = wB - [|x|] - 1.
Proof.
- intros; unfold znz_opp_carry, znz_to_Z; auto.
+ intros; unfold opp_carry, to_Z; auto.
replace (- x - 1) with (- 1 - x) by omega.
rewrite <- Zminus_mod_idemp_r.
replace ( -1 - x mod wB) with (0 + ( -1 - x mod wB)) by omega.
@@ -194,21 +182,21 @@ Section ZModulo.
generalize (Z_mod_lt x wB wB_pos); omega.
Qed.
- Definition znz_succ_c x :=
+ Definition succ_c x :=
let y := Zsucc x in
- if znz_eq0 y then C1 0 else C0 y.
+ if eq0 y then C1 0 else C0 y.
- Definition znz_add_c x y :=
+ Definition add_c x y :=
let z := [|x|] + [|y|] in
if Z_lt_le_dec z wB then C0 z else C1 (z-wB).
- Definition znz_add_carry_c x y :=
+ Definition add_carry_c x y :=
let z := [|x|]+[|y|]+1 in
if Z_lt_le_dec z wB then C0 z else C1 (z-wB).
- Definition znz_succ := Zsucc.
- Definition znz_add := Zplus.
- Definition znz_add_carry x y := x + y + 1.
+ Definition succ := Zsucc.
+ Definition add := Zplus.
+ Definition add_carry x y := x + y + 1.
Lemma Zmod_equal :
forall x y z, z>0 -> (x-y) mod z = 0 -> x mod z = y mod z.
@@ -221,10 +209,10 @@ Section ZModulo.
rewrite Zplus_comm, Zmult_comm, Z_mod_plus; auto.
Qed.
- Lemma spec_succ_c : forall x, [+|znz_succ_c x|] = [|x|] + 1.
+ Lemma spec_succ_c : forall x, [+|succ_c x|] = [|x|] + 1.
Proof.
- intros; unfold znz_succ_c, znz_to_Z, Zsucc.
- case_eq (znz_eq0 (x+1)); intros; unfold interp_carry.
+ intros; unfold succ_c, to_Z, Zsucc.
+ case_eq (eq0 (x+1)); intros; unfold interp_carry.
rewrite Zmult_1_l.
replace (wB + 0 mod wB) with wB by auto with zarith.
@@ -236,7 +224,7 @@ Section ZModulo.
apply Zmod_equal; auto.
assert ((x+1) mod wB <> 0).
- unfold znz_eq0, znz_to_Z in *; now destruct ((x+1) mod wB).
+ unfold eq0, to_Z in *; now destruct ((x+1) mod wB).
assert (x mod wB + 1 <> wB).
contradict H0.
rewrite Zeq_plus_swap in H0; simpl in H0.
@@ -247,9 +235,9 @@ Section ZModulo.
generalize (Z_mod_lt x wB wB_pos); omega.
Qed.
- Lemma spec_add_c : forall x y, [+|znz_add_c x y|] = [|x|] + [|y|].
+ Lemma spec_add_c : forall x y, [+|add_c x y|] = [|x|] + [|y|].
Proof.
- intros; unfold znz_add_c, znz_to_Z, interp_carry.
+ intros; unfold add_c, to_Z, interp_carry.
destruct Z_lt_le_dec.
apply Zmod_small;
generalize (Z_mod_lt x wB wB_pos) (Z_mod_lt y wB wB_pos); omega.
@@ -258,9 +246,9 @@ Section ZModulo.
generalize (Z_mod_lt x wB wB_pos) (Z_mod_lt y wB wB_pos); omega.
Qed.
- Lemma spec_add_carry_c : forall x y, [+|znz_add_carry_c x y|] = [|x|] + [|y|] + 1.
+ Lemma spec_add_carry_c : forall x y, [+|add_carry_c x y|] = [|x|] + [|y|] + 1.
Proof.
- intros; unfold znz_add_carry_c, znz_to_Z, interp_carry.
+ intros; unfold add_carry_c, to_Z, interp_carry.
destruct Z_lt_le_dec.
apply Zmod_small;
generalize (Z_mod_lt x wB wB_pos) (Z_mod_lt y wB wB_pos); omega.
@@ -269,59 +257,59 @@ Section ZModulo.
generalize (Z_mod_lt x wB wB_pos) (Z_mod_lt y wB wB_pos); omega.
Qed.
- Lemma spec_succ : forall x, [|znz_succ x|] = ([|x|] + 1) mod wB.
+ Lemma spec_succ : forall x, [|succ x|] = ([|x|] + 1) mod wB.
Proof.
- intros; unfold znz_succ, znz_to_Z, Zsucc.
+ intros; unfold succ, to_Z, Zsucc.
symmetry; apply Zplus_mod_idemp_l.
Qed.
- Lemma spec_add : forall x y, [|znz_add x y|] = ([|x|] + [|y|]) mod wB.
+ Lemma spec_add : forall x y, [|add x y|] = ([|x|] + [|y|]) mod wB.
Proof.
- intros; unfold znz_add, znz_to_Z; apply Zplus_mod.
+ intros; unfold add, to_Z; apply Zplus_mod.
Qed.
Lemma spec_add_carry :
- forall x y, [|znz_add_carry x y|] = ([|x|] + [|y|] + 1) mod wB.
+ forall x y, [|add_carry x y|] = ([|x|] + [|y|] + 1) mod wB.
Proof.
- intros; unfold znz_add_carry, znz_to_Z.
+ intros; unfold add_carry, to_Z.
rewrite <- Zplus_mod_idemp_l.
rewrite (Zplus_mod x y).
rewrite Zplus_mod_idemp_l; auto.
Qed.
- Definition znz_pred_c x :=
- if znz_eq0 x then C1 (wB-1) else C0 (x-1).
+ Definition pred_c x :=
+ if eq0 x then C1 (wB-1) else C0 (x-1).
- Definition znz_sub_c x y :=
+ Definition sub_c x y :=
let z := [|x|]-[|y|] in
if Z_lt_le_dec z 0 then C1 (wB+z) else C0 z.
- Definition znz_sub_carry_c x y :=
+ Definition sub_carry_c x y :=
let z := [|x|]-[|y|]-1 in
if Z_lt_le_dec z 0 then C1 (wB+z) else C0 z.
- Definition znz_pred := Zpred.
- Definition znz_sub := Zminus.
- Definition znz_sub_carry x y := x - y - 1.
+ Definition pred := Zpred.
+ Definition sub := Zminus.
+ Definition sub_carry x y := x - y - 1.
- Lemma spec_pred_c : forall x, [-|znz_pred_c x|] = [|x|] - 1.
+ Lemma spec_pred_c : forall x, [-|pred_c x|] = [|x|] - 1.
Proof.
- intros; unfold znz_pred_c, znz_to_Z, interp_carry.
- case_eq (znz_eq0 x); intros.
+ intros; unfold pred_c, to_Z, interp_carry.
+ case_eq (eq0 x); intros.
fold [|x|]; rewrite spec_eq0; auto.
replace ((wB-1) mod wB) with (wB-1); auto with zarith.
symmetry; apply Zmod_small; generalize wB_pos; omega.
assert (x mod wB <> 0).
- unfold znz_eq0, znz_to_Z in *; now destruct (x mod wB).
+ unfold eq0, to_Z in *; now destruct (x mod wB).
rewrite <- Zminus_mod_idemp_l.
apply Zmod_small.
generalize (Z_mod_lt x wB wB_pos); omega.
Qed.
- Lemma spec_sub_c : forall x y, [-|znz_sub_c x y|] = [|x|] - [|y|].
+ Lemma spec_sub_c : forall x y, [-|sub_c x y|] = [|x|] - [|y|].
Proof.
- intros; unfold znz_sub_c, znz_to_Z, interp_carry.
+ intros; unfold sub_c, to_Z, interp_carry.
destruct Z_lt_le_dec.
replace ((wB + (x mod wB - y mod wB)) mod wB) with
(wB + (x mod wB - y mod wB)).
@@ -333,9 +321,9 @@ Section ZModulo.
generalize wB_pos (Z_mod_lt x wB wB_pos) (Z_mod_lt y wB wB_pos); omega.
Qed.
- Lemma spec_sub_carry_c : forall x y, [-|znz_sub_carry_c x y|] = [|x|] - [|y|] - 1.
+ Lemma spec_sub_carry_c : forall x y, [-|sub_carry_c x y|] = [|x|] - [|y|] - 1.
Proof.
- intros; unfold znz_sub_carry_c, znz_to_Z, interp_carry.
+ intros; unfold sub_carry_c, to_Z, interp_carry.
destruct Z_lt_le_dec.
replace ((wB + (x mod wB - y mod wB - 1)) mod wB) with
(wB + (x mod wB - y mod wB -1)).
@@ -347,38 +335,38 @@ Section ZModulo.
generalize wB_pos (Z_mod_lt x wB wB_pos) (Z_mod_lt y wB wB_pos); omega.
Qed.
- Lemma spec_pred : forall x, [|znz_pred x|] = ([|x|] - 1) mod wB.
+ Lemma spec_pred : forall x, [|pred x|] = ([|x|] - 1) mod wB.
Proof.
- intros; unfold znz_pred, znz_to_Z, Zpred.
+ intros; unfold pred, to_Z, Zpred.
rewrite <- Zplus_mod_idemp_l; auto.
Qed.
- Lemma spec_sub : forall x y, [|znz_sub x y|] = ([|x|] - [|y|]) mod wB.
+ Lemma spec_sub : forall x y, [|sub x y|] = ([|x|] - [|y|]) mod wB.
Proof.
- intros; unfold znz_sub, znz_to_Z; apply Zminus_mod.
+ intros; unfold sub, to_Z; apply Zminus_mod.
Qed.
Lemma spec_sub_carry :
- forall x y, [|znz_sub_carry x y|] = ([|x|] - [|y|] - 1) mod wB.
+ forall x y, [|sub_carry x y|] = ([|x|] - [|y|] - 1) mod wB.
Proof.
- intros; unfold znz_sub_carry, znz_to_Z.
+ intros; unfold sub_carry, to_Z.
rewrite <- Zminus_mod_idemp_l.
rewrite (Zminus_mod x y).
rewrite Zminus_mod_idemp_l.
auto.
Qed.
- Definition znz_mul_c x y :=
+ Definition mul_c x y :=
let (h,l) := Zdiv_eucl ([|x|]*[|y|]) wB in
- if znz_eq0 h then if znz_eq0 l then W0 else WW h l else WW h l.
+ if eq0 h then if eq0 l then W0 else WW h l else WW h l.
- Definition znz_mul := Zmult.
+ Definition mul := Zmult.
- Definition znz_square_c x := znz_mul_c x x.
+ Definition square_c x := mul_c x x.
- Lemma spec_mul_c : forall x y, [|| znz_mul_c x y ||] = [|x|] * [|y|].
+ Lemma spec_mul_c : forall x y, [|| mul_c x y ||] = [|x|] * [|y|].
Proof.
- intros; unfold znz_mul_c, zn2z_to_Z.
+ intros; unfold mul_c, zn2z_to_Z.
assert (Zdiv_eucl ([|x|]*[|y|]) wB = (([|x|]*[|y|])/wB,([|x|]*[|y|]) mod wB)).
unfold Zmod, Zdiv; destruct Zdiv_eucl; auto.
generalize (Z_div_mod ([|x|]*[|y|]) wB wB_pos); destruct Zdiv_eucl as (h,l).
@@ -394,31 +382,31 @@ Section ZModulo.
apply Zdiv_lt_upper_bound; auto with zarith.
apply Zmult_lt_compat; auto with zarith.
clear H H0 H1 H2.
- case_eq (znz_eq0 h); simpl; intros.
- case_eq (znz_eq0 l); simpl; intros.
+ case_eq (eq0 h); simpl; intros.
+ case_eq (eq0 l); simpl; intros.
rewrite <- H3, <- H4, (spec_eq0 h), (spec_eq0 l); auto with zarith.
rewrite H3, H4; auto with zarith.
rewrite H3, H4; auto with zarith.
Qed.
- Lemma spec_mul : forall x y, [|znz_mul x y|] = ([|x|] * [|y|]) mod wB.
+ Lemma spec_mul : forall x y, [|mul x y|] = ([|x|] * [|y|]) mod wB.
Proof.
- intros; unfold znz_mul, znz_to_Z; apply Zmult_mod.
+ intros; unfold mul, to_Z; apply Zmult_mod.
Qed.
- Lemma spec_square_c : forall x, [|| znz_square_c x||] = [|x|] * [|x|].
+ Lemma spec_square_c : forall x, [|| square_c x||] = [|x|] * [|x|].
Proof.
intros x; exact (spec_mul_c x x).
Qed.
- Definition znz_div x y := Zdiv_eucl [|x|] [|y|].
+ Definition div x y := Zdiv_eucl [|x|] [|y|].
Lemma spec_div : forall a b, 0 < [|b|] ->
- let (q,r) := znz_div a b in
+ let (q,r) := div a b in
[|a|] = [|q|] * [|b|] + [|r|] /\
0 <= [|r|] < [|b|].
Proof.
- intros; unfold znz_div.
+ intros; unfold div.
assert ([|b|]>0) by auto with zarith.
assert (Zdiv_eucl [|a|] [|b|] = ([|a|]/[|b|], [|a|] mod [|b|])).
unfold Zmod, Zdiv; destruct Zdiv_eucl; auto.
@@ -440,10 +428,10 @@ Section ZModulo.
rewrite H5, H6; rewrite Zmult_comm; auto with zarith.
Qed.
- Definition znz_div_gt := znz_div.
+ Definition div_gt := div.
Lemma spec_div_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
- let (q,r) := znz_div_gt a b in
+ let (q,r) := div_gt a b in
[|a|] = [|q|] * [|b|] + [|r|] /\
0 <= [|r|] < [|b|].
Proof.
@@ -451,34 +439,34 @@ Section ZModulo.
apply spec_div; auto.
Qed.
- Definition znz_mod x y := [|x|] mod [|y|].
- Definition znz_mod_gt x y := [|x|] mod [|y|].
+ Definition modulo x y := [|x|] mod [|y|].
+ Definition modulo_gt x y := [|x|] mod [|y|].
- Lemma spec_mod : forall a b, 0 < [|b|] ->
- [|znz_mod a b|] = [|a|] mod [|b|].
+ Lemma spec_modulo : forall a b, 0 < [|b|] ->
+ [|modulo a b|] = [|a|] mod [|b|].
Proof.
- intros; unfold znz_mod.
+ intros; unfold modulo.
apply Zmod_small.
assert ([|b|]>0) by auto with zarith.
generalize (Z_mod_lt [|a|] [|b|] H0) (Z_mod_lt b wB wB_pos).
fold [|b|]; omega.
Qed.
- Lemma spec_mod_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
- [|znz_mod_gt a b|] = [|a|] mod [|b|].
+ Lemma spec_modulo_gt : forall a b, [|a|] > [|b|] -> 0 < [|b|] ->
+ [|modulo_gt a b|] = [|a|] mod [|b|].
Proof.
- intros; apply spec_mod; auto.
+ intros; apply spec_modulo; auto.
Qed.
- Definition znz_gcd x y := Zgcd [|x|] [|y|].
- Definition znz_gcd_gt x y := Zgcd [|x|] [|y|].
+ Definition gcd x y := Zgcd [|x|] [|y|].
+ Definition gcd_gt x y := Zgcd [|x|] [|y|].
Lemma Zgcd_bound : forall a b, 0<=a -> 0<=b -> Zgcd a b <= Zmax a b.
Proof.
intros.
generalize (Zgcd_is_gcd a b); inversion_clear 1.
- destruct H2; destruct H3; clear H4.
- assert (H3:=Zgcd_is_pos a b).
+ destruct H2 as (q,H2); destruct H3 as (q',H3); clear H4.
+ assert (H4:=Zgcd_is_pos a b).
destruct (Z_eq_dec (Zgcd a b) 0).
rewrite e; generalize (Zmax_spec a b); omega.
assert (0 <= q).
@@ -489,15 +477,15 @@ Section ZModulo.
generalize (Zmax_spec 0 b) (Zabs_spec b); omega.
apply Zle_trans with a.
- rewrite H1 at 2.
+ rewrite H2 at 2.
rewrite <- (Zmult_1_l (Zgcd a b)) at 1.
apply Zmult_le_compat; auto with zarith.
generalize (Zmax_spec a b); omega.
Qed.
- Lemma spec_gcd : forall a b, Zis_gcd [|a|] [|b|] [|znz_gcd a b|].
+ Lemma spec_gcd : forall a b, Zis_gcd [|a|] [|b|] [|gcd a b|].
Proof.
- intros; unfold znz_gcd.
+ intros; unfold gcd.
generalize (Z_mod_lt a wB wB_pos)(Z_mod_lt b wB wB_pos); intros.
fold [|a|] in *; fold [|b|] in *.
replace ([|Zgcd [|a|] [|b|]|]) with (Zgcd [|a|] [|b|]).
@@ -511,22 +499,22 @@ Section ZModulo.
Qed.
Lemma spec_gcd_gt : forall a b, [|a|] > [|b|] ->
- Zis_gcd [|a|] [|b|] [|znz_gcd_gt a b|].
+ Zis_gcd [|a|] [|b|] [|gcd_gt a b|].
Proof.
intros. apply spec_gcd; auto.
Qed.
- Definition znz_div21 a1 a2 b :=
+ Definition div21 a1 a2 b :=
Zdiv_eucl ([|a1|]*wB+[|a2|]) [|b|].
Lemma spec_div21 : forall a1 a2 b,
wB/2 <= [|b|] ->
[|a1|] < [|b|] ->
- let (q,r) := znz_div21 a1 a2 b in
+ let (q,r) := div21 a1 a2 b in
[|a1|] *wB+ [|a2|] = [|q|] * [|b|] + [|r|] /\
0 <= [|r|] < [|b|].
Proof.
- intros; unfold znz_div21.
+ intros; unfold div21.
generalize (Z_mod_lt a1 wB wB_pos); fold [|a1|]; intros.
generalize (Z_mod_lt a2 wB wB_pos); fold [|a2|]; intros.
assert ([|b|]>0) by auto with zarith.
@@ -552,22 +540,22 @@ Section ZModulo.
rewrite H8, H9; rewrite Zmult_comm; auto with zarith.
Qed.
- Definition znz_add_mul_div p x y :=
- ([|x|] * (2 ^ [|p|]) + [|y|] / (2 ^ ((Zpos znz_digits) - [|p|]))).
+ Definition add_mul_div p x y :=
+ ([|x|] * (2 ^ [|p|]) + [|y|] / (2 ^ ((Zpos digits) - [|p|]))).
Lemma spec_add_mul_div : forall x y p,
- [|p|] <= Zpos znz_digits ->
- [| znz_add_mul_div p x y |] =
+ [|p|] <= Zpos digits ->
+ [| add_mul_div p x y |] =
([|x|] * (2 ^ [|p|]) +
- [|y|] / (2 ^ ((Zpos znz_digits) - [|p|]))) mod wB.
+ [|y|] / (2 ^ ((Zpos digits) - [|p|]))) mod wB.
Proof.
- intros; unfold znz_add_mul_div; auto.
+ intros; unfold add_mul_div; auto.
Qed.
- Definition znz_pos_mod p w := [|w|] mod (2 ^ [|p|]).
+ Definition pos_mod p w := [|w|] mod (2 ^ [|p|]).
Lemma spec_pos_mod : forall w p,
- [|znz_pos_mod p w|] = [|w|] mod (2 ^ [|p|]).
+ [|pos_mod p w|] = [|w|] mod (2 ^ [|p|]).
Proof.
- intros; unfold znz_pos_mod.
+ intros; unfold pos_mod.
apply Zmod_small.
generalize (Z_mod_lt [|w|] (2 ^ [|p|])); intros.
split.
@@ -576,65 +564,58 @@ Section ZModulo.
apply Zmod_le; auto with zarith.
Qed.
- Definition znz_is_even x :=
+ Definition is_even x :=
if Z_eq_dec ([|x|] mod 2) 0 then true else false.
Lemma spec_is_even : forall x,
- if znz_is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1.
+ if is_even x then [|x|] mod 2 = 0 else [|x|] mod 2 = 1.
Proof.
- intros; unfold znz_is_even; destruct Z_eq_dec; auto.
+ intros; unfold is_even; destruct Z_eq_dec; auto.
generalize (Z_mod_lt [|x|] 2); omega.
Qed.
- Definition znz_sqrt x := Zsqrt_plain [|x|].
+ Definition sqrt x := Z.sqrt [|x|].
Lemma spec_sqrt : forall x,
- [|znz_sqrt x|] ^ 2 <= [|x|] < ([|znz_sqrt x|] + 1) ^ 2.
+ [|sqrt x|] ^ 2 <= [|x|] < ([|sqrt x|] + 1) ^ 2.
Proof.
intros.
- unfold znz_sqrt.
+ unfold sqrt.
repeat rewrite Zpower_2.
- replace [|Zsqrt_plain [|x|]|] with (Zsqrt_plain [|x|]).
- apply Zsqrt_interval; auto with zarith.
+ replace [|Z.sqrt [|x|]|] with (Z.sqrt [|x|]).
+ apply Z.sqrt_spec; auto with zarith.
symmetry; apply Zmod_small.
- split.
- apply Zsqrt_plain_is_pos; auto with zarith.
-
- cut (Zsqrt_plain [|x|] <= (wB-1)); try omega.
- rewrite <- (Zsqrt_square_id (wB-1)).
- apply Zsqrt_le.
- split; auto.
- apply Zle_trans with (wB-1); auto with zarith.
- generalize (spec_to_Z x); auto with zarith.
- apply Zsquare_le.
- generalize wB_pos; auto with zarith.
+ split. apply Z.sqrt_nonneg; auto.
+ apply Zle_lt_trans with [|x|]; auto.
+ apply Z.sqrt_le_lin; auto.
Qed.
- Definition znz_sqrt2 x y :=
+ Definition sqrt2 x y :=
let z := [|x|]*wB+[|y|] in
match z with
| Z0 => (0, C0 0)
| Zpos p =>
- let (s,r,_,_) := sqrtrempos p in
+ let (s,r) := Z.sqrtrem (Zpos p) in
(s, if Z_lt_le_dec r wB then C0 r else C1 (r-wB))
| Zneg _ => (0, C0 0)
end.
Lemma spec_sqrt2 : forall x y,
wB/ 4 <= [|x|] ->
- let (s,r) := znz_sqrt2 x y in
+ let (s,r) := sqrt2 x y in
[||WW x y||] = [|s|] ^ 2 + [+|r|] /\
[+|r|] <= 2 * [|s|].
Proof.
- intros; unfold znz_sqrt2.
+ intros; unfold sqrt2.
simpl zn2z_to_Z.
remember ([|x|]*wB+[|y|]) as z.
destruct z.
auto with zarith.
- destruct sqrtrempos; intros.
+ generalize (Z.sqrtrem_spec (Zpos p)).
+ destruct Z.sqrtrem as (s,r); intros [U V]; auto with zarith.
assert (s < wB).
destruct (Z_lt_le_dec s wB); auto.
assert (wB * wB <= Zpos p).
- rewrite e.
+ rewrite U.
apply Zle_trans with (s*s); try omega.
apply Zmult_le_compat; generalize wB_pos; auto with zarith.
assert (Zpos p < wB*wB).
@@ -665,15 +646,15 @@ Section ZModulo.
apply two_power_pos_correct.
Qed.
- Definition znz_head0 x := match [|x|] with
- | Z0 => znz_zdigits
- | Zpos p => znz_zdigits - log_inf p - 1
+ Definition head0 x := match [|x|] with
+ | Z0 => zdigits
+ | Zpos p => zdigits - log_inf p - 1
| _ => 0
end.
- Lemma spec_head00: forall x, [|x|] = 0 -> [|znz_head0 x|] = Zpos znz_digits.
+ Lemma spec_head00: forall x, [|x|] = 0 -> [|head0 x|] = Zpos digits.
Proof.
- unfold znz_head0; intros.
+ unfold head0; intros.
rewrite H; simpl.
apply spec_zdigits.
Qed.
@@ -701,43 +682,43 @@ Section ZModulo.
Lemma spec_head0 : forall x, 0 < [|x|] ->
- wB/ 2 <= 2 ^ ([|znz_head0 x|]) * [|x|] < wB.
+ wB/ 2 <= 2 ^ ([|head0 x|]) * [|x|] < wB.
Proof.
- intros; unfold znz_head0.
+ intros; unfold head0.
generalize (spec_to_Z x).
destruct [|x|]; try discriminate.
intros.
destruct (log_inf_correct p).
rewrite 2 two_p_power2 in H2; auto with zarith.
- assert (0 <= znz_zdigits - log_inf p - 1 < wB).
+ assert (0 <= zdigits - log_inf p - 1 < wB).
split.
- cut (log_inf p < znz_zdigits); try omega.
- unfold znz_zdigits.
+ cut (log_inf p < zdigits); try omega.
+ unfold zdigits.
unfold wB, base in *.
apply log_inf_bounded; auto with zarith.
- apply Zlt_trans with znz_zdigits.
+ apply Zlt_trans with zdigits.
omega.
- unfold znz_zdigits, wB, base; apply Zpower2_lt_lin; auto with zarith.
+ unfold zdigits, wB, base; apply Zpower2_lt_lin; auto with zarith.
- unfold znz_to_Z; rewrite (Zmod_small _ _ H3).
+ unfold to_Z; rewrite (Zmod_small _ _ H3).
destruct H2.
split.
- apply Zle_trans with (2^(znz_zdigits - log_inf p - 1)*(2^log_inf p)).
+ apply Zle_trans with (2^(zdigits - log_inf p - 1)*(2^log_inf p)).
apply Zdiv_le_upper_bound; auto with zarith.
rewrite <- Zpower_exp; auto with zarith.
rewrite Zmult_comm; rewrite <- Zpower_Zsucc; auto with zarith.
- replace (Zsucc (znz_zdigits - log_inf p -1 +log_inf p)) with znz_zdigits
+ replace (Zsucc (zdigits - log_inf p -1 +log_inf p)) with zdigits
by ring.
- unfold wB, base, znz_zdigits; auto with zarith.
+ unfold wB, base, zdigits; auto with zarith.
apply Zmult_le_compat; auto with zarith.
apply Zlt_le_trans
- with (2^(znz_zdigits - log_inf p - 1)*(2^(Zsucc (log_inf p)))).
+ with (2^(zdigits - log_inf p - 1)*(2^(Zsucc (log_inf p)))).
apply Zmult_lt_compat_l; auto with zarith.
rewrite <- Zpower_exp; auto with zarith.
- replace (znz_zdigits - log_inf p -1 +Zsucc (log_inf p)) with znz_zdigits
+ replace (zdigits - log_inf p -1 +Zsucc (log_inf p)) with zdigits
by ring.
- unfold wB, base, znz_zdigits; auto with zarith.
+ unfold wB, base, zdigits; auto with zarith.
Qed.
Fixpoint Ptail p := match p with
@@ -774,24 +755,24 @@ Section ZModulo.
rewrite <- H1; omega.
Qed.
- Definition znz_tail0 x :=
+ Definition tail0 x :=
match [|x|] with
- | Z0 => znz_zdigits
+ | Z0 => zdigits
| Zpos p => Ptail p
| Zneg _ => 0
end.
- Lemma spec_tail00: forall x, [|x|] = 0 -> [|znz_tail0 x|] = Zpos znz_digits.
+ Lemma spec_tail00: forall x, [|x|] = 0 -> [|tail0 x|] = Zpos digits.
Proof.
- unfold znz_tail0; intros.
+ unfold tail0; intros.
rewrite H; simpl.
apply spec_zdigits.
Qed.
Lemma spec_tail0 : forall x, 0 < [|x|] ->
- exists y, 0 <= y /\ [|x|] = (2 * y + 1) * (2 ^ [|znz_tail0 x|]).
+ exists y, 0 <= y /\ [|x|] = (2 * y + 1) * (2 ^ [|tail0 x|]).
Proof.
- intros; unfold znz_tail0.
+ intros; unfold tail0.
generalize (spec_to_Z x).
destruct [|x|]; try discriminate; intros.
assert ([|Ptail p|] = Ptail p).
@@ -818,60 +799,60 @@ Section ZModulo.
(** Let's now group everything in two records *)
- Definition zmod_op := mk_znz_op
- (znz_digits : positive)
- (znz_zdigits: znz)
- (znz_to_Z : znz -> Z)
- (znz_of_pos : positive -> N * znz)
- (znz_head0 : znz -> znz)
- (znz_tail0 : znz -> znz)
-
- (znz_0 : znz)
- (znz_1 : znz)
- (znz_Bm1 : znz)
-
- (znz_compare : znz -> znz -> comparison)
- (znz_eq0 : znz -> bool)
-
- (znz_opp_c : znz -> carry znz)
- (znz_opp : znz -> znz)
- (znz_opp_carry : znz -> znz)
-
- (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)
-
- (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 : znz -> znz -> znz -> znz)
- (znz_pos_mod : znz -> znz -> znz)
-
- (znz_is_even : znz -> bool)
- (znz_sqrt2 : znz -> znz -> znz * carry znz)
- (znz_sqrt : znz -> znz).
-
- Definition zmod_spec := mk_znz_spec zmod_op
+ Instance zmod_ops : ZnZ.Ops Z := ZnZ.MkOps
+ (digits : positive)
+ (zdigits: t)
+ (to_Z : t -> Z)
+ (of_pos : positive -> N * t)
+ (head0 : t -> t)
+ (tail0 : t -> t)
+
+ (zero : t)
+ (one : t)
+ (minus_one : t)
+
+ (compare : t -> t -> comparison)
+ (eq0 : t -> bool)
+
+ (opp_c : t -> carry t)
+ (opp : t -> t)
+ (opp_carry : t -> t)
+
+ (succ_c : t -> carry t)
+ (add_c : t -> t -> carry t)
+ (add_carry_c : t -> t -> carry t)
+ (succ : t -> t)
+ (add : t -> t -> t)
+ (add_carry : t -> t -> t)
+
+ (pred_c : t -> carry t)
+ (sub_c : t -> t -> carry t)
+ (sub_carry_c : t -> t -> carry t)
+ (pred : t -> t)
+ (sub : t -> t -> t)
+ (sub_carry : t -> t -> t)
+
+ (mul_c : t -> t -> zn2z t)
+ (mul : t -> t -> t)
+ (square_c : t -> zn2z t)
+
+ (div21 : t -> t -> t -> t*t)
+ (div_gt : t -> t -> t * t)
+ (div : t -> t -> t * t)
+
+ (modulo_gt : t -> t -> t)
+ (modulo : t -> t -> t)
+
+ (gcd_gt : t -> t -> t)
+ (gcd : t -> t -> t)
+ (add_mul_div : t -> t -> t -> t)
+ (pos_mod : t -> t -> t)
+
+ (is_even : t -> bool)
+ (sqrt2 : t -> t -> t * carry t)
+ (sqrt : t -> t).
+
+ Instance zmod_specs : ZnZ.Specs zmod_ops := ZnZ.MkSpecs
spec_to_Z
spec_of_pos
spec_zdigits
@@ -910,8 +891,8 @@ Section ZModulo.
spec_div_gt
spec_div
- spec_mod_gt
- spec_mod
+ spec_modulo_gt
+ spec_modulo
spec_gcd_gt
spec_gcd
@@ -934,12 +915,12 @@ End ZModulo.
Module Type PositiveNotOne.
Parameter p : positive.
- Axiom not_one : p<> 1%positive.
+ Axiom not_one : p <> 1%positive.
End PositiveNotOne.
Module ZModuloCyclicType (P:PositiveNotOne) <: CyclicType.
- Definition w := Z.
- Definition w_op := zmod_op P.p.
- Definition w_spec := zmod_spec P.not_one.
+ Definition t := Z.
+ Instance ops : ZnZ.Ops t := zmod_ops P.p.
+ Instance specs : ZnZ.Specs ops := zmod_specs P.not_one.
End ZModuloCyclicType.
diff --git a/theories/Numbers/Integer/Abstract/ZAdd.v b/theories/Numbers/Integer/Abstract/ZAdd.v
index d9624ea3..647ab0ac 100644
--- a/theories/Numbers/Integer/Abstract/ZAdd.v
+++ b/theories/Numbers/Integer/Abstract/ZAdd.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,34 +8,33 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZAdd.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export ZBase.
-Module ZAddPropFunct (Import Z : ZAxiomsSig').
-Include ZBasePropFunct Z.
+Module ZAddProp (Import Z : ZAxiomsMiniSig').
+Include ZBaseProp Z.
(** Theorems that are either not valid on N or have different proofs
on N and Z *)
+Hint Rewrite opp_0 : nz.
+
Theorem add_pred_l : forall n m, P n + m == P (n + m).
Proof.
intros n m.
rewrite <- (succ_pred n) at 2.
-rewrite add_succ_l. now rewrite pred_succ.
+now rewrite add_succ_l, pred_succ.
Qed.
Theorem add_pred_r : forall n m, n + P m == P (n + m).
Proof.
-intros n m; rewrite (add_comm n (P m)), (add_comm n m);
-apply add_pred_l.
+intros n m; rewrite 2 (add_comm n); apply add_pred_l.
Qed.
Theorem add_opp_r : forall n m, n + (- m) == n - m.
Proof.
nzinduct m.
-rewrite opp_0; rewrite sub_0_r; now rewrite add_0_r.
-intro m. rewrite opp_succ, sub_succ_r, add_pred_r; now rewrite pred_inj_wd.
+now nzsimpl.
+intro m. rewrite opp_succ, sub_succ_r, add_pred_r. now rewrite pred_inj_wd.
Qed.
Theorem sub_0_l : forall n, 0 - n == - n.
@@ -45,7 +44,7 @@ Qed.
Theorem sub_succ_l : forall n m, S n - m == S (n - m).
Proof.
-intros n m; do 2 rewrite <- add_opp_r; now rewrite add_succ_l.
+intros n m; rewrite <- 2 add_opp_r; now rewrite add_succ_l.
Qed.
Theorem sub_pred_l : forall n m, P n - m == P (n - m).
@@ -69,7 +68,7 @@ Qed.
Theorem sub_diag : forall n, n - n == 0.
Proof.
nzinduct n.
-now rewrite sub_0_r.
+now nzsimpl.
intro n. rewrite sub_succ_r, sub_succ_l; now rewrite pred_succ.
Qed.
@@ -90,20 +89,20 @@ Qed.
Theorem add_sub_assoc : forall n m p, n + (m - p) == (n + m) - p.
Proof.
-intros n m p; do 2 rewrite <- add_opp_r; now rewrite add_assoc.
+intros n m p; rewrite <- 2 add_opp_r; now rewrite add_assoc.
Qed.
Theorem opp_involutive : forall n, - (- n) == n.
Proof.
nzinduct n.
-now do 2 rewrite opp_0.
-intro n. rewrite opp_succ, opp_pred; now rewrite succ_inj_wd.
+now nzsimpl.
+intro n. rewrite opp_succ, opp_pred. now rewrite succ_inj_wd.
Qed.
Theorem opp_add_distr : forall n m, - (n + m) == - n + (- m).
Proof.
intros n m; nzinduct n.
-rewrite opp_0; now do 2 rewrite add_0_l.
+now nzsimpl.
intro n. rewrite add_succ_l; do 2 rewrite opp_succ; rewrite add_pred_l.
now rewrite pred_inj_wd.
Qed.
@@ -116,12 +115,12 @@ Qed.
Theorem opp_inj : forall n m, - n == - m -> n == m.
Proof.
-intros n m H. apply opp_wd in H. now do 2 rewrite opp_involutive in H.
+intros n m H. apply opp_wd in H. now rewrite 2 opp_involutive in H.
Qed.
Theorem opp_inj_wd : forall n m, - n == - m <-> n == m.
Proof.
-intros n m; split; [apply opp_inj | apply opp_wd].
+intros n m; split; [apply opp_inj | intros; now f_equiv].
Qed.
Theorem eq_opp_l : forall n m, - n == m <-> n == - m.
@@ -137,7 +136,7 @@ Qed.
Theorem sub_add_distr : forall n m p, n - (m + p) == (n - m) - p.
Proof.
intros n m p; rewrite <- add_opp_r, opp_add_distr, add_assoc.
-now do 2 rewrite add_opp_r.
+now rewrite 2 add_opp_r.
Qed.
Theorem sub_sub_distr : forall n m p, n - (m - p) == (n - m) + p.
@@ -148,7 +147,7 @@ Qed.
Theorem sub_opp_l : forall n m, - n - m == - m - n.
Proof.
-intros n m. do 2 rewrite <- add_opp_r. now rewrite add_comm.
+intros n m. rewrite <- 2 add_opp_r. now rewrite add_comm.
Qed.
Theorem sub_opp_r : forall n m, n - (- m) == n + m.
@@ -165,7 +164,7 @@ Qed.
Theorem sub_cancel_l : forall n m p, n - m == n - p <-> m == p.
Proof.
intros n m p. rewrite <- (add_cancel_l (n - m) (n - p) (- n)).
-do 2 rewrite add_sub_assoc. rewrite add_opp_diag_l; do 2 rewrite sub_0_l.
+rewrite 2 add_sub_assoc. rewrite add_opp_diag_l; rewrite 2 sub_0_l.
apply opp_inj_wd.
Qed.
@@ -252,6 +251,11 @@ Proof.
intros; now rewrite <- sub_sub_distr, sub_diag, sub_0_r.
Qed.
+Theorem sub_add : forall n m, m - n + n == m.
+Proof.
+ intros. now rewrite <- add_sub_swap, add_simpl_r.
+Qed.
+
(** Now we have two sums or differences; the name includes the two
operators and the position of the terms being canceled *)
@@ -289,5 +293,5 @@ Qed.
(** Of course, there are many other variants *)
-End ZAddPropFunct.
+End ZAddProp.
diff --git a/theories/Numbers/Integer/Abstract/ZAddOrder.v b/theories/Numbers/Integer/Abstract/ZAddOrder.v
index 6ce54f88..423cdf58 100644
--- a/theories/Numbers/Integer/Abstract/ZAddOrder.v
+++ b/theories/Numbers/Integer/Abstract/ZAddOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,180 +8,173 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZAddOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export ZLt.
-Module ZAddOrderPropFunct (Import Z : ZAxiomsSig').
-Include ZOrderPropFunct Z.
+Module ZAddOrderProp (Import Z : ZAxiomsMiniSig').
+Include ZOrderProp Z.
(** Theorems that are either not valid on N or have different proofs
on N and Z *)
Theorem add_neg_neg : forall n m, n < 0 -> m < 0 -> n + m < 0.
Proof.
-intros n m H1 H2. rewrite <- (add_0_l 0). now apply add_lt_mono.
+intros. rewrite <- (add_0_l 0). now apply add_lt_mono.
Qed.
Theorem add_neg_nonpos : forall n m, n < 0 -> m <= 0 -> n + m < 0.
Proof.
-intros n m H1 H2. rewrite <- (add_0_l 0). now apply add_lt_le_mono.
+intros. rewrite <- (add_0_l 0). now apply add_lt_le_mono.
Qed.
Theorem add_nonpos_neg : forall n m, n <= 0 -> m < 0 -> n + m < 0.
Proof.
-intros n m H1 H2. rewrite <- (add_0_l 0). now apply add_le_lt_mono.
+intros. rewrite <- (add_0_l 0). now apply add_le_lt_mono.
Qed.
Theorem add_nonpos_nonpos : forall n m, n <= 0 -> m <= 0 -> n + m <= 0.
Proof.
-intros n m H1 H2. rewrite <- (add_0_l 0). now apply add_le_mono.
+intros. rewrite <- (add_0_l 0). now apply add_le_mono.
Qed.
(** Sub and order *)
Theorem lt_0_sub : forall n m, 0 < m - n <-> n < m.
Proof.
-intros n m. stepl (0 + n < m - n + n) by symmetry; apply add_lt_mono_r.
-rewrite add_0_l; now rewrite sub_simpl_r.
+intros n m. now rewrite (add_lt_mono_r _ _ n), add_0_l, sub_simpl_r.
Qed.
Notation sub_pos := lt_0_sub (only parsing).
Theorem le_0_sub : forall n m, 0 <= m - n <-> n <= m.
Proof.
-intros n m; stepl (0 + n <= m - n + n) by symmetry; apply add_le_mono_r.
-rewrite add_0_l; now rewrite sub_simpl_r.
+intros n m. now rewrite (add_le_mono_r _ _ n), add_0_l, sub_simpl_r.
Qed.
Notation sub_nonneg := le_0_sub (only parsing).
Theorem lt_sub_0 : forall n m, n - m < 0 <-> n < m.
Proof.
-intros n m. stepl (n - m + m < 0 + m) by symmetry; apply add_lt_mono_r.
-rewrite add_0_l; now rewrite sub_simpl_r.
+intros n m. now rewrite (add_lt_mono_r _ _ m), add_0_l, sub_simpl_r.
Qed.
Notation sub_neg := lt_sub_0 (only parsing).
Theorem le_sub_0 : forall n m, n - m <= 0 <-> n <= m.
Proof.
-intros n m. stepl (n - m + m <= 0 + m) by symmetry; apply add_le_mono_r.
-rewrite add_0_l; now rewrite sub_simpl_r.
+intros n m. now rewrite (add_le_mono_r _ _ m), add_0_l, sub_simpl_r.
Qed.
Notation sub_nonpos := le_sub_0 (only parsing).
Theorem opp_lt_mono : forall n m, n < m <-> - m < - n.
Proof.
-intros n m. stepr (m + - m < m + - n) by symmetry; apply add_lt_mono_l.
-do 2 rewrite add_opp_r. rewrite sub_diag. symmetry; apply lt_0_sub.
+intros n m. now rewrite <- lt_0_sub, <- add_opp_l, <- sub_opp_r, lt_0_sub.
Qed.
Theorem opp_le_mono : forall n m, n <= m <-> - m <= - n.
Proof.
-intros n m. stepr (m + - m <= m + - n) by symmetry; apply add_le_mono_l.
-do 2 rewrite add_opp_r. rewrite sub_diag. symmetry; apply le_0_sub.
+intros n m. now rewrite <- le_0_sub, <- add_opp_l, <- sub_opp_r, le_0_sub.
Qed.
Theorem opp_pos_neg : forall n, 0 < - n <-> n < 0.
Proof.
-intro n; rewrite (opp_lt_mono n 0); now rewrite opp_0.
+intro n; now rewrite (opp_lt_mono n 0), opp_0.
Qed.
Theorem opp_neg_pos : forall n, - n < 0 <-> 0 < n.
Proof.
-intro n. rewrite (opp_lt_mono 0 n). now rewrite opp_0.
+intro n. now rewrite (opp_lt_mono 0 n), opp_0.
Qed.
Theorem opp_nonneg_nonpos : forall n, 0 <= - n <-> n <= 0.
Proof.
-intro n; rewrite (opp_le_mono n 0); now rewrite opp_0.
+intro n; now rewrite (opp_le_mono n 0), opp_0.
Qed.
Theorem opp_nonpos_nonneg : forall n, - n <= 0 <-> 0 <= n.
Proof.
-intro n. rewrite (opp_le_mono 0 n). now rewrite opp_0.
+intro n. now rewrite (opp_le_mono 0 n), opp_0.
+Qed.
+
+Theorem lt_m1_0 : -1 < 0.
+Proof.
+apply opp_neg_pos, lt_0_1.
Qed.
Theorem sub_lt_mono_l : forall n m p, n < m <-> p - m < p - n.
Proof.
-intros n m p. do 2 rewrite <- add_opp_r. rewrite <- add_lt_mono_l.
-apply opp_lt_mono.
+intros. now rewrite <- 2 add_opp_r, <- add_lt_mono_l, opp_lt_mono.
Qed.
Theorem sub_lt_mono_r : forall n m p, n < m <-> n - p < m - p.
Proof.
-intros n m p; do 2 rewrite <- add_opp_r; apply add_lt_mono_r.
+intros. now rewrite <- 2 add_opp_r, add_lt_mono_r.
Qed.
Theorem sub_lt_mono : forall n m p q, n < m -> q < p -> n - p < m - q.
Proof.
intros n m p q H1 H2.
apply lt_trans with (m - p);
-[now apply -> sub_lt_mono_r | now apply -> sub_lt_mono_l].
+[now apply sub_lt_mono_r | now apply sub_lt_mono_l].
Qed.
Theorem sub_le_mono_l : forall n m p, n <= m <-> p - m <= p - n.
Proof.
-intros n m p; do 2 rewrite <- add_opp_r; rewrite <- add_le_mono_l;
-apply opp_le_mono.
+intros. now rewrite <- 2 add_opp_r, <- add_le_mono_l, opp_le_mono.
Qed.
Theorem sub_le_mono_r : forall n m p, n <= m <-> n - p <= m - p.
Proof.
-intros n m p; do 2 rewrite <- add_opp_r; apply add_le_mono_r.
+intros. now rewrite <- 2 add_opp_r, add_le_mono_r.
Qed.
Theorem sub_le_mono : forall n m p q, n <= m -> q <= p -> n - p <= m - q.
Proof.
intros n m p q H1 H2.
apply le_trans with (m - p);
-[now apply -> sub_le_mono_r | now apply -> sub_le_mono_l].
+[now apply sub_le_mono_r | now apply sub_le_mono_l].
Qed.
Theorem sub_lt_le_mono : forall n m p q, n < m -> q <= p -> n - p < m - q.
Proof.
intros n m p q H1 H2.
apply lt_le_trans with (m - p);
-[now apply -> sub_lt_mono_r | now apply -> sub_le_mono_l].
+[now apply sub_lt_mono_r | now apply sub_le_mono_l].
Qed.
Theorem sub_le_lt_mono : forall n m p q, n <= m -> q < p -> n - p < m - q.
Proof.
intros n m p q H1 H2.
apply le_lt_trans with (m - p);
-[now apply -> sub_le_mono_r | now apply -> sub_lt_mono_l].
+[now apply sub_le_mono_r | now apply sub_lt_mono_l].
Qed.
Theorem le_lt_sub_lt : forall n m p q, n <= m -> p - n < q - m -> p < q.
Proof.
intros n m p q H1 H2. apply (le_lt_add_lt (- m) (- n));
-[now apply -> opp_le_mono | now do 2 rewrite add_opp_r].
+[now apply -> opp_le_mono | now rewrite 2 add_opp_r].
Qed.
Theorem lt_le_sub_lt : forall n m p q, n < m -> p - n <= q - m -> p < q.
Proof.
intros n m p q H1 H2. apply (lt_le_add_lt (- m) (- n));
-[now apply -> opp_lt_mono | now do 2 rewrite add_opp_r].
+[now apply -> opp_lt_mono | now rewrite 2 add_opp_r].
Qed.
Theorem le_le_sub_lt : forall n m p q, n <= m -> p - n <= q - m -> p <= q.
Proof.
intros n m p q H1 H2. apply (le_le_add_le (- m) (- n));
-[now apply -> opp_le_mono | now do 2 rewrite add_opp_r].
+[now apply -> opp_le_mono | now rewrite 2 add_opp_r].
Qed.
Theorem lt_add_lt_sub_r : forall n m p, n + p < m <-> n < m - p.
Proof.
-intros n m p. stepl (n + p - p < m - p) by symmetry; apply sub_lt_mono_r.
-now rewrite add_simpl_r.
+intros n m p. now rewrite (sub_lt_mono_r _ _ p), add_simpl_r.
Qed.
Theorem le_add_le_sub_r : forall n m p, n + p <= m <-> n <= m - p.
Proof.
-intros n m p. stepl (n + p - p <= m - p) by symmetry; apply sub_le_mono_r.
-now rewrite add_simpl_r.
+intros n m p. now rewrite (sub_le_mono_r _ _ p), add_simpl_r.
Qed.
Theorem lt_add_lt_sub_l : forall n m p, n + p < m <-> p < m - n.
@@ -196,14 +189,12 @@ Qed.
Theorem lt_sub_lt_add_r : forall n m p, n - p < m <-> n < m + p.
Proof.
-intros n m p. stepl (n - p + p < m + p) by symmetry; apply add_lt_mono_r.
-now rewrite sub_simpl_r.
+intros n m p. now rewrite (add_lt_mono_r _ _ p), sub_simpl_r.
Qed.
Theorem le_sub_le_add_r : forall n m p, n - p <= m <-> n <= m + p.
Proof.
-intros n m p. stepl (n - p + p <= m + p) by symmetry; apply add_le_mono_r.
-now rewrite sub_simpl_r.
+intros n m p. now rewrite (add_le_mono_r _ _ p), sub_simpl_r.
Qed.
Theorem lt_sub_lt_add_l : forall n m p, n - m < p <-> n < m + p.
@@ -218,74 +209,68 @@ Qed.
Theorem lt_sub_lt_add : forall n m p q, n - m < p - q <-> n + q < m + p.
Proof.
-intros n m p q. rewrite lt_sub_lt_add_l. rewrite add_sub_assoc.
-now rewrite <- lt_add_lt_sub_r.
+intros n m p q. now rewrite lt_sub_lt_add_l, add_sub_assoc, <- lt_add_lt_sub_r.
Qed.
Theorem le_sub_le_add : forall n m p q, n - m <= p - q <-> n + q <= m + p.
Proof.
-intros n m p q. rewrite le_sub_le_add_l. rewrite add_sub_assoc.
-now rewrite <- le_add_le_sub_r.
+intros n m p q. now rewrite le_sub_le_add_l, add_sub_assoc, <- le_add_le_sub_r.
Qed.
Theorem lt_sub_pos : forall n m, 0 < m <-> n - m < n.
Proof.
-intros n m. stepr (n - m < n - 0) by now rewrite sub_0_r. apply sub_lt_mono_l.
+intros n m. now rewrite (sub_lt_mono_l _ _ n), sub_0_r.
Qed.
Theorem le_sub_nonneg : forall n m, 0 <= m <-> n - m <= n.
Proof.
-intros n m. stepr (n - m <= n - 0) by now rewrite sub_0_r. apply sub_le_mono_l.
+intros n m. now rewrite (sub_le_mono_l _ _ n), sub_0_r.
Qed.
Theorem sub_lt_cases : forall n m p q, n - m < p - q -> n < m \/ q < p.
Proof.
-intros n m p q H. rewrite lt_sub_lt_add in H. now apply add_lt_cases.
+intros. now apply add_lt_cases, lt_sub_lt_add.
Qed.
Theorem sub_le_cases : forall n m p q, n - m <= p - q -> n <= m \/ q <= p.
Proof.
-intros n m p q H. rewrite le_sub_le_add in H. now apply add_le_cases.
+intros. now apply add_le_cases, le_sub_le_add.
Qed.
Theorem sub_neg_cases : forall n m, n - m < 0 -> n < 0 \/ 0 < m.
Proof.
-intros n m H; rewrite <- add_opp_r in H.
-setoid_replace (0 < m) with (- m < 0) using relation iff by (symmetry; apply opp_neg_pos).
-now apply add_neg_cases.
+intros.
+rewrite <- (opp_neg_pos m). apply add_neg_cases. now rewrite add_opp_r.
Qed.
Theorem sub_pos_cases : forall n m, 0 < n - m -> 0 < n \/ m < 0.
Proof.
-intros n m H; rewrite <- add_opp_r in H.
-setoid_replace (m < 0) with (0 < - m) using relation iff by (symmetry; apply opp_pos_neg).
-now apply add_pos_cases.
+intros.
+rewrite <- (opp_pos_neg m). apply add_pos_cases. now rewrite add_opp_r.
Qed.
Theorem sub_nonpos_cases : forall n m, n - m <= 0 -> n <= 0 \/ 0 <= m.
Proof.
-intros n m H; rewrite <- add_opp_r in H.
-setoid_replace (0 <= m) with (- m <= 0) using relation iff by (symmetry; apply opp_nonpos_nonneg).
-now apply add_nonpos_cases.
+intros.
+rewrite <- (opp_nonpos_nonneg m). apply add_nonpos_cases. now rewrite add_opp_r.
Qed.
Theorem sub_nonneg_cases : forall n m, 0 <= n - m -> 0 <= n \/ m <= 0.
Proof.
-intros n m H; rewrite <- add_opp_r in H.
-setoid_replace (m <= 0) with (0 <= - m) using relation iff by (symmetry; apply opp_nonneg_nonpos).
-now apply add_nonneg_cases.
+intros.
+rewrite <- (opp_nonneg_nonpos m). apply add_nonneg_cases. now rewrite add_opp_r.
Qed.
Section PosNeg.
Variable P : Z.t -> Prop.
-Hypothesis P_wd : Proper (Z.eq ==> iff) P.
+Hypothesis P_wd : Proper (eq ==> iff) P.
Theorem zero_pos_neg :
P 0 -> (forall n, 0 < n -> P n /\ P (- n)) -> forall n, P n.
Proof.
intros H1 H2 n. destruct (lt_trichotomy n 0) as [H3 | [H3 | H3]].
-apply <- opp_pos_neg in H3. apply H2 in H3. destruct H3 as [_ H3].
+apply opp_pos_neg, H2 in H3. destruct H3 as [_ H3].
now rewrite opp_involutive in H3.
now rewrite H3.
apply H2 in H3; now destruct H3.
@@ -295,6 +280,6 @@ End PosNeg.
Ltac zero_pos_neg n := induction_maker n ltac:(apply zero_pos_neg).
-End ZAddOrderPropFunct.
+End ZAddOrderProp.
diff --git a/theories/Numbers/Integer/Abstract/ZAxioms.v b/theories/Numbers/Integer/Abstract/ZAxioms.v
index fd14cff0..fd20ce72 100644
--- a/theories/Numbers/Integer/Abstract/ZAxioms.v
+++ b/theories/Numbers/Integer/Abstract/ZAxioms.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,11 +8,19 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZAxioms.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NZAxioms.
+Require Import Bool NZParity NZPow NZSqrt NZLog NZGcd NZDiv NZBits.
+
+(** We obtain integers by postulating that successor of predecessor
+ is identity. *)
+
+Module Type ZAxiom (Import Z : NZAxiomsSig').
+ Axiom succ_pred : forall n, S (P n) == n.
+End ZAxiom.
-Set Implicit Arguments.
+(** For historical reasons, ZAxiomsMiniSig isn't just NZ + ZAxiom,
+ we also add an [opp] function, that can be seen as a shortcut
+ for [sub 0]. *)
Module Type Opp (Import T:Typ).
Parameter Inline opp : t -> t.
@@ -24,15 +32,91 @@ End OppNotation.
Module Type Opp' (T:Typ) := Opp T <+ OppNotation T.
-(** We obtain integers by postulating that every number has a predecessor. *)
-
Module Type IsOpp (Import Z : NZAxiomsSig')(Import O : Opp' Z).
Declare Instance opp_wd : Proper (eq==>eq) opp.
- Axiom succ_pred : forall n, S (P n) == n.
Axiom opp_0 : - 0 == 0.
Axiom opp_succ : forall n, - (S n) == P (- n).
End IsOpp.
-Module Type ZAxiomsSig := NZOrdAxiomsSig <+ Opp <+ IsOpp.
-Module Type ZAxiomsSig' := NZOrdAxiomsSig' <+ Opp' <+ IsOpp.
+Module Type OppCstNotation (Import A : NZAxiomsSig)(Import B : Opp A).
+ Notation "- 1" := (opp one).
+ Notation "- 2" := (opp two).
+End OppCstNotation.
+
+Module Type ZAxiomsMiniSig := NZOrdAxiomsSig <+ ZAxiom <+ Opp <+ IsOpp.
+Module Type ZAxiomsMiniSig' := NZOrdAxiomsSig' <+ ZAxiom <+ Opp' <+ IsOpp
+ <+ OppCstNotation.
+
+
+(** Other functions and their specifications *)
+
+(** Absolute value *)
+
+Module Type HasAbs(Import Z : ZAxiomsMiniSig').
+ Parameter Inline abs : t -> t.
+ Axiom abs_eq : forall n, 0<=n -> abs n == n.
+ Axiom abs_neq : forall n, n<=0 -> abs n == -n.
+End HasAbs.
+
+(** A sign function *)
+
+Module Type HasSgn (Import Z : ZAxiomsMiniSig').
+ Parameter Inline sgn : t -> t.
+ Axiom sgn_null : forall n, n==0 -> sgn n == 0.
+ Axiom sgn_pos : forall n, 0<n -> sgn n == 1.
+ Axiom sgn_neg : forall n, n<0 -> sgn n == -1.
+End HasSgn.
+
+(** Divisions *)
+
+(** First, the usual Coq convention of Truncated-Toward-Bottom
+ (a.k.a Floor). We simply extend the NZ signature. *)
+
+Module Type ZDivSpecific (Import A:ZAxiomsMiniSig')(Import B : DivMod' A).
+ Axiom mod_pos_bound : forall a b, 0 < b -> 0 <= a mod b < b.
+ Axiom mod_neg_bound : forall a b, b < 0 -> b < a mod b <= 0.
+End ZDivSpecific.
+
+Module Type ZDiv (Z:ZAxiomsMiniSig) := NZDiv.NZDiv Z <+ ZDivSpecific Z.
+Module Type ZDiv' (Z:ZAxiomsMiniSig) := NZDiv.NZDiv' Z <+ ZDivSpecific Z.
+
+(** Then, the Truncated-Toward-Zero convention.
+ For not colliding with Floor operations, we use different names
+*)
+
+Module Type QuotRem (Import A : Typ).
+ Parameters Inline quot rem : t -> t -> t.
+End QuotRem.
+
+Module Type QuotRemNotation (A : Typ)(Import B : QuotRem A).
+ Infix "÷" := quot (at level 40, left associativity).
+ Infix "rem" := rem (at level 40, no associativity).
+End QuotRemNotation.
+
+Module Type QuotRem' (A : Typ) := QuotRem A <+ QuotRemNotation A.
+
+Module Type QuotRemSpec (Import A : ZAxiomsMiniSig')(Import B : QuotRem' A).
+ Declare Instance quot_wd : Proper (eq==>eq==>eq) quot.
+ Declare Instance rem_wd : Proper (eq==>eq==>eq) B.rem.
+ Axiom quot_rem : forall a b, b ~= 0 -> a == b*(a÷b) + (a rem b).
+ Axiom rem_bound_pos : forall a b, 0<=a -> 0<b -> 0 <= a rem b < b.
+ Axiom rem_opp_l : forall a b, b ~= 0 -> (-a) rem b == - (a rem b).
+ Axiom rem_opp_r : forall a b, b ~= 0 -> a rem (-b) == a rem b.
+End QuotRemSpec.
+
+Module Type ZQuot (Z:ZAxiomsMiniSig) := QuotRem Z <+ QuotRemSpec Z.
+Module Type ZQuot' (Z:ZAxiomsMiniSig) := QuotRem' Z <+ QuotRemSpec Z.
+
+(** For all other functions, the NZ axiomatizations are enough. *)
+
+(** Let's group everything *)
+
+Module Type ZAxiomsSig := ZAxiomsMiniSig <+ OrderFunctions
+ <+ HasAbs <+ HasSgn <+ NZParity.NZParity
+ <+ NZPow.NZPow <+ NZSqrt.NZSqrt <+ NZLog.NZLog2 <+ NZGcd.NZGcd
+ <+ ZDiv <+ ZQuot <+ NZBits.NZBits <+ NZSquare.
+Module Type ZAxiomsSig' := ZAxiomsMiniSig' <+ OrderFunctions'
+ <+ HasAbs <+ HasSgn <+ NZParity.NZParity
+ <+ NZPow.NZPow' <+ NZSqrt.NZSqrt' <+ NZLog.NZLog2 <+ NZGcd.NZGcd'
+ <+ ZDiv' <+ ZQuot' <+ NZBits.NZBits' <+ NZSquare.
diff --git a/theories/Numbers/Integer/Abstract/ZBase.v b/theories/Numbers/Integer/Abstract/ZBase.v
index aa7979ae..51054852 100644
--- a/theories/Numbers/Integer/Abstract/ZBase.v
+++ b/theories/Numbers/Integer/Abstract/ZBase.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,26 +8,29 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZBase.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export Decidable.
Require Export ZAxioms.
Require Import NZProperties.
-Module ZBasePropFunct (Import Z : ZAxiomsSig').
-Include NZPropFunct Z.
+Module ZBaseProp (Import Z : ZAxiomsMiniSig').
+Include NZProp Z.
(* Theorems that are true for integers but not for natural numbers *)
Theorem pred_inj : forall n m, P n == P m -> n == m.
Proof.
-intros n m H. apply succ_wd in H. now do 2 rewrite succ_pred in H.
+intros n m H. apply succ_wd in H. now rewrite 2 succ_pred in H.
Qed.
Theorem pred_inj_wd : forall n1 n2, P n1 == P n2 <-> n1 == n2.
Proof.
-intros n1 n2; split; [apply pred_inj | apply pred_wd].
+intros n1 n2; split; [apply pred_inj | intros; now f_equiv].
+Qed.
+
+Lemma succ_m1 : S (-1) == 0.
+Proof.
+ now rewrite one_succ, opp_succ, opp_0, succ_pred.
Qed.
-End ZBasePropFunct.
+End ZBaseProp.
diff --git a/theories/Numbers/Integer/Abstract/ZBits.v b/theories/Numbers/Integer/Abstract/ZBits.v
new file mode 100644
index 00000000..92afbcb5
--- /dev/null
+++ b/theories/Numbers/Integer/Abstract/ZBits.v
@@ -0,0 +1,1947 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import
+ Bool ZAxioms ZMulOrder ZPow ZDivFloor ZSgnAbs ZParity NZLog.
+
+(** Derived properties of bitwise operations *)
+
+Module Type ZBitsProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZParityProp A B)
+ (Import D : ZSgnAbsProp A B)
+ (Import E : ZPowProp A B C D)
+ (Import F : ZDivProp A B D)
+ (Import G : NZLog2Prop A A A B E).
+
+Include BoolEqualityFacts A.
+
+Ltac order_nz := try apply pow_nonzero; order'.
+Ltac order_pos' := try apply abs_nonneg; order_pos.
+Hint Rewrite div_0_l mod_0_l div_1_r mod_1_r : nz.
+
+(** Some properties of power and division *)
+
+Lemma pow_sub_r : forall a b c, a~=0 -> 0<=c<=b -> a^(b-c) == a^b / a^c.
+Proof.
+ intros a b c Ha (H,H'). rewrite <- (sub_simpl_r b c) at 2.
+ rewrite pow_add_r; trivial.
+ rewrite div_mul. reflexivity.
+ now apply pow_nonzero.
+ now apply le_0_sub.
+Qed.
+
+Lemma pow_div_l : forall a b c, b~=0 -> 0<=c -> a mod b == 0 ->
+ (a/b)^c == a^c / b^c.
+Proof.
+ intros a b c Hb Hc H. rewrite (div_mod a b Hb) at 2.
+ rewrite H, add_0_r, pow_mul_l, mul_comm, div_mul. reflexivity.
+ now apply pow_nonzero.
+Qed.
+
+(** An injection from bits [true] and [false] to numbers 1 and 0.
+ We declare it as a (local) coercion for shorter statements. *)
+
+Definition b2z (b:bool) := if b then 1 else 0.
+Local Coercion b2z : bool >-> t.
+
+Instance b2z_wd : Proper (Logic.eq ==> eq) b2z := _.
+
+Lemma exists_div2 a : exists a' (b:bool), a == 2*a' + b.
+Proof.
+ elim (Even_or_Odd a); [intros (a',H)| intros (a',H)].
+ exists a'. exists false. now nzsimpl.
+ exists a'. exists true. now simpl.
+Qed.
+
+(** We can compact [testbit_odd_0] [testbit_even_0]
+ [testbit_even_succ] [testbit_odd_succ] in only two lemmas. *)
+
+Lemma testbit_0_r a (b:bool) : testbit (2*a+b) 0 = b.
+Proof.
+ destruct b; simpl; rewrite ?add_0_r.
+ apply testbit_odd_0.
+ apply testbit_even_0.
+Qed.
+
+Lemma testbit_succ_r a (b:bool) n : 0<=n ->
+ testbit (2*a+b) (succ n) = testbit a n.
+Proof.
+ destruct b; simpl; rewrite ?add_0_r.
+ now apply testbit_odd_succ.
+ now apply testbit_even_succ.
+Qed.
+
+(** Alternative caracterisations of [testbit] *)
+
+(** This concise equation could have been taken as specification
+ for testbit in the interface, but it would have been hard to
+ implement with little initial knowledge about div and mod *)
+
+Lemma testbit_spec' a n : 0<=n -> a.[n] == (a / 2^n) mod 2.
+Proof.
+ intro Hn. revert a. apply le_ind with (4:=Hn).
+ solve_proper.
+ intros a. nzsimpl.
+ destruct (exists_div2 a) as (a' & b & H). rewrite H at 1.
+ rewrite testbit_0_r. apply mod_unique with a'; trivial.
+ left. destruct b; split; simpl; order'.
+ clear n Hn. intros n Hn IH a.
+ destruct (exists_div2 a) as (a' & b & H). rewrite H at 1.
+ rewrite testbit_succ_r, IH by trivial. f_equiv.
+ rewrite pow_succ_r, <- div_div by order_pos. f_equiv.
+ apply div_unique with b; trivial.
+ left. destruct b; split; simpl; order'.
+Qed.
+
+(** This caracterisation that uses only basic operations and
+ power was initially taken as specification for testbit.
+ We describe [a] as having a low part and a high part, with
+ the corresponding bit in the middle. This caracterisation
+ is moderatly complex to implement, but also moderately
+ usable... *)
+
+Lemma testbit_spec a n : 0<=n ->
+ exists l h, 0<=l<2^n /\ a == l + (a.[n] + 2*h)*2^n.
+Proof.
+ intro Hn. exists (a mod 2^n). exists (a / 2^n / 2). split.
+ apply mod_pos_bound; order_pos.
+ rewrite add_comm, mul_comm, (add_comm a.[n]).
+ rewrite (div_mod a (2^n)) at 1 by order_nz. do 2 f_equiv.
+ rewrite testbit_spec' by trivial. apply div_mod. order'.
+Qed.
+
+Lemma testbit_true : forall a n, 0<=n ->
+ (a.[n] = true <-> (a / 2^n) mod 2 == 1).
+Proof.
+ intros a n Hn.
+ rewrite <- testbit_spec' by trivial.
+ destruct a.[n]; split; simpl; now try order'.
+Qed.
+
+Lemma testbit_false : forall a n, 0<=n ->
+ (a.[n] = false <-> (a / 2^n) mod 2 == 0).
+Proof.
+ intros a n Hn.
+ rewrite <- testbit_spec' by trivial.
+ destruct a.[n]; split; simpl; now try order'.
+Qed.
+
+Lemma testbit_eqb : forall a n, 0<=n ->
+ a.[n] = eqb ((a / 2^n) mod 2) 1.
+Proof.
+ intros a n Hn.
+ apply eq_true_iff_eq. now rewrite testbit_true, eqb_eq.
+Qed.
+
+(** Results about the injection [b2z] *)
+
+Lemma b2z_inj : forall (a0 b0:bool), a0 == b0 -> a0 = b0.
+Proof.
+ intros [|] [|]; simpl; trivial; order'.
+Qed.
+
+Lemma add_b2z_double_div2 : forall (a0:bool) a, (a0+2*a)/2 == a.
+Proof.
+ intros a0 a. rewrite mul_comm, div_add by order'.
+ now rewrite div_small, add_0_l by (destruct a0; split; simpl; order').
+Qed.
+
+Lemma add_b2z_double_bit0 : forall (a0:bool) a, (a0+2*a).[0] = a0.
+Proof.
+ intros a0 a. apply b2z_inj.
+ rewrite testbit_spec' by order.
+ nzsimpl. rewrite mul_comm, mod_add by order'.
+ now rewrite mod_small by (destruct a0; split; simpl; order').
+Qed.
+
+Lemma b2z_div2 : forall (a0:bool), a0/2 == 0.
+Proof.
+ intros a0. rewrite <- (add_b2z_double_div2 a0 0). now nzsimpl.
+Qed.
+
+Lemma b2z_bit0 : forall (a0:bool), a0.[0] = a0.
+Proof.
+ intros a0. rewrite <- (add_b2z_double_bit0 a0 0) at 2. now nzsimpl.
+Qed.
+
+(** The specification of testbit by low and high parts is complete *)
+
+Lemma testbit_unique : forall a n (a0:bool) l h,
+ 0<=l<2^n -> a == l + (a0 + 2*h)*2^n -> a.[n] = a0.
+Proof.
+ intros a n a0 l h Hl EQ.
+ assert (0<=n).
+ destruct (le_gt_cases 0 n) as [Hn|Hn]; trivial.
+ rewrite pow_neg_r in Hl by trivial. destruct Hl; order.
+ apply b2z_inj. rewrite testbit_spec' by trivial.
+ symmetry. apply mod_unique with h.
+ left; destruct a0; simpl; split; order'.
+ symmetry. apply div_unique with l.
+ now left.
+ now rewrite add_comm, (add_comm _ a0), mul_comm.
+Qed.
+
+(** All bits of number 0 are 0 *)
+
+Lemma bits_0 : forall n, 0.[n] = false.
+Proof.
+ intros n.
+ destruct (le_gt_cases 0 n).
+ apply testbit_false; trivial. nzsimpl; order_nz.
+ now apply testbit_neg_r.
+Qed.
+
+(** For negative numbers, we are actually doing two's complement *)
+
+Lemma bits_opp : forall a n, 0<=n -> (-a).[n] = negb (P a).[n].
+Proof.
+ intros a n Hn.
+ destruct (testbit_spec (-a) n Hn) as (l & h & Hl & EQ).
+ fold (b2z (-a).[n]) in EQ.
+ apply negb_sym.
+ apply testbit_unique with (2^n-l-1) (-h-1).
+ split.
+ apply lt_succ_r. rewrite sub_1_r, succ_pred. now apply lt_0_sub.
+ apply le_succ_l. rewrite sub_1_r, succ_pred. apply le_sub_le_add_r.
+ rewrite <- (add_0_r (2^n)) at 1. now apply add_le_mono_l.
+ rewrite <- add_sub_swap, sub_1_r. f_equiv.
+ apply opp_inj. rewrite opp_add_distr, opp_sub_distr.
+ rewrite (add_comm _ l), <- add_assoc.
+ rewrite EQ at 1. apply add_cancel_l.
+ rewrite <- opp_add_distr.
+ rewrite <- (mul_1_l (2^n)) at 2. rewrite <- mul_add_distr_r.
+ rewrite <- mul_opp_l.
+ f_equiv.
+ rewrite !opp_add_distr.
+ rewrite <- mul_opp_r.
+ rewrite opp_sub_distr, opp_involutive.
+ rewrite (add_comm h).
+ rewrite mul_add_distr_l.
+ rewrite !add_assoc.
+ apply add_cancel_r.
+ rewrite mul_1_r.
+ rewrite add_comm, add_assoc, !add_opp_r, sub_1_r, two_succ, pred_succ.
+ destruct (-a).[n]; simpl. now rewrite sub_0_r. now nzsimpl'.
+Qed.
+
+(** All bits of number (-1) are 1 *)
+
+Lemma bits_m1 : forall n, 0<=n -> (-1).[n] = true.
+Proof.
+ intros. now rewrite bits_opp, one_succ, pred_succ, bits_0.
+Qed.
+
+(** Various ways to refer to the lowest bit of a number *)
+
+Lemma bit0_odd : forall a, a.[0] = odd a.
+Proof.
+ intros. symmetry.
+ destruct (exists_div2 a) as (a' & b & EQ).
+ rewrite EQ, testbit_0_r, add_comm, odd_add_mul_2.
+ destruct b; simpl; apply odd_1 || apply odd_0.
+Qed.
+
+Lemma bit0_eqb : forall a, a.[0] = eqb (a mod 2) 1.
+Proof.
+ intros a. rewrite testbit_eqb by order. now nzsimpl.
+Qed.
+
+Lemma bit0_mod : forall a, a.[0] == a mod 2.
+Proof.
+ intros a. rewrite testbit_spec' by order. now nzsimpl.
+Qed.
+
+(** Hence testing a bit is equivalent to shifting and testing parity *)
+
+Lemma testbit_odd : forall a n, a.[n] = odd (a>>n).
+Proof.
+ intros. now rewrite <- bit0_odd, shiftr_spec, add_0_l.
+Qed.
+
+(** [log2] gives the highest nonzero bit of positive numbers *)
+
+Lemma bit_log2 : forall a, 0<a -> a.[log2 a] = true.
+Proof.
+ intros a Ha.
+ assert (Ha' := log2_nonneg a).
+ destruct (log2_spec_alt a Ha) as (r & EQ & Hr).
+ rewrite EQ at 1.
+ rewrite testbit_true, add_comm by trivial.
+ rewrite <- (mul_1_l (2^log2 a)) at 1.
+ rewrite div_add by order_nz.
+ rewrite div_small; trivial.
+ rewrite add_0_l. apply mod_small. split; order'.
+Qed.
+
+Lemma bits_above_log2 : forall a n, 0<=a -> log2 a < n ->
+ a.[n] = false.
+Proof.
+ intros a n Ha H.
+ assert (Hn : 0<=n).
+ transitivity (log2 a). apply log2_nonneg. order'.
+ rewrite testbit_false by trivial.
+ rewrite div_small. nzsimpl; order'.
+ split. order. apply log2_lt_cancel. now rewrite log2_pow2.
+Qed.
+
+(** Hence the number of bits of [a] is [1+log2 a]
+ (see [Psize] and [Psize_pos]).
+*)
+
+(** For negative numbers, things are the other ways around:
+ log2 gives the highest zero bit (for numbers below -1).
+*)
+
+Lemma bit_log2_neg : forall a, a < -1 -> a.[log2 (P (-a))] = false.
+Proof.
+ intros a Ha.
+ rewrite <- (opp_involutive a) at 1.
+ rewrite bits_opp.
+ apply negb_false_iff.
+ apply bit_log2.
+ apply opp_lt_mono in Ha. rewrite opp_involutive in Ha.
+ apply lt_succ_lt_pred. now rewrite <- one_succ.
+ apply log2_nonneg.
+Qed.
+
+Lemma bits_above_log2_neg : forall a n, a < 0 -> log2 (P (-a)) < n ->
+ a.[n] = true.
+Proof.
+ intros a n Ha H.
+ assert (Hn : 0<=n).
+ transitivity (log2 (P (-a))). apply log2_nonneg. order'.
+ rewrite <- (opp_involutive a), bits_opp, negb_true_iff by trivial.
+ apply bits_above_log2; trivial.
+ now rewrite <- opp_succ, opp_nonneg_nonpos, le_succ_l.
+Qed.
+
+(** Accesing a high enough bit of a number gives its sign *)
+
+Lemma bits_iff_nonneg : forall a n, log2 (abs a) < n ->
+ (0<=a <-> a.[n] = false).
+Proof.
+ intros a n Hn. split; intros H.
+ rewrite abs_eq in Hn; trivial. now apply bits_above_log2.
+ destruct (le_gt_cases 0 a); trivial.
+ rewrite abs_neq in Hn by order.
+ rewrite bits_above_log2_neg in H; try easy.
+ apply le_lt_trans with (log2 (-a)); trivial.
+ apply log2_le_mono. apply le_pred_l.
+Qed.
+
+Lemma bits_iff_nonneg' : forall a,
+ 0<=a <-> a.[S (log2 (abs a))] = false.
+Proof.
+ intros. apply bits_iff_nonneg. apply lt_succ_diag_r.
+Qed.
+
+Lemma bits_iff_nonneg_ex : forall a,
+ 0<=a <-> (exists k, forall m, k<m -> a.[m] = false).
+Proof.
+ intros a. split.
+ intros Ha. exists (log2 a). intros m Hm. now apply bits_above_log2.
+ intros (k,Hk). destruct (le_gt_cases k (log2 (abs a))).
+ now apply bits_iff_nonneg', Hk, lt_succ_r.
+ apply (bits_iff_nonneg a (S k)).
+ now apply lt_succ_r, lt_le_incl.
+ apply Hk. apply lt_succ_diag_r.
+Qed.
+
+Lemma bits_iff_neg : forall a n, log2 (abs a) < n ->
+ (a<0 <-> a.[n] = true).
+Proof.
+ intros a n Hn.
+ now rewrite lt_nge, <- not_false_iff_true, (bits_iff_nonneg a n).
+Qed.
+
+Lemma bits_iff_neg' : forall a, a<0 <-> a.[S (log2 (abs a))] = true.
+Proof.
+ intros. apply bits_iff_neg. apply lt_succ_diag_r.
+Qed.
+
+Lemma bits_iff_neg_ex : forall a,
+ a<0 <-> (exists k, forall m, k<m -> a.[m] = true).
+Proof.
+ intros a. split.
+ intros Ha. exists (log2 (P (-a))). intros m Hm. now apply bits_above_log2_neg.
+ intros (k,Hk). destruct (le_gt_cases k (log2 (abs a))).
+ now apply bits_iff_neg', Hk, lt_succ_r.
+ apply (bits_iff_neg a (S k)).
+ now apply lt_succ_r, lt_le_incl.
+ apply Hk. apply lt_succ_diag_r.
+Qed.
+
+(** Testing bits after division or multiplication by a power of two *)
+
+Lemma div2_bits : forall a n, 0<=n -> (a/2).[n] = a.[S n].
+Proof.
+ intros a n Hn.
+ apply eq_true_iff_eq. rewrite 2 testbit_true by order_pos.
+ rewrite pow_succ_r by trivial.
+ now rewrite div_div by order_pos.
+Qed.
+
+Lemma div_pow2_bits : forall a n m, 0<=n -> 0<=m -> (a/2^n).[m] = a.[m+n].
+Proof.
+ intros a n m Hn. revert a m. apply le_ind with (4:=Hn).
+ solve_proper.
+ intros a m Hm. now nzsimpl.
+ clear n Hn. intros n Hn IH a m Hm. nzsimpl; trivial.
+ rewrite <- div_div by order_pos.
+ now rewrite IH, div2_bits by order_pos.
+Qed.
+
+Lemma double_bits_succ : forall a n, (2*a).[S n] = a.[n].
+Proof.
+ intros a n.
+ destruct (le_gt_cases 0 n) as [Hn|Hn].
+ now rewrite <- div2_bits, mul_comm, div_mul by order'.
+ rewrite (testbit_neg_r a n Hn).
+ apply le_succ_l in Hn. le_elim Hn.
+ now rewrite testbit_neg_r.
+ now rewrite Hn, bit0_odd, odd_mul, odd_2.
+Qed.
+
+Lemma double_bits : forall a n, (2*a).[n] = a.[P n].
+Proof.
+ intros a n. rewrite <- (succ_pred n) at 1. apply double_bits_succ.
+Qed.
+
+Lemma mul_pow2_bits_add : forall a n m, 0<=n -> (a*2^n).[n+m] = a.[m].
+Proof.
+ intros a n m Hn. revert a m. apply le_ind with (4:=Hn).
+ solve_proper.
+ intros a m. now nzsimpl.
+ clear n Hn. intros n Hn IH a m. nzsimpl; trivial.
+ rewrite mul_assoc, (mul_comm _ 2), <- mul_assoc.
+ now rewrite double_bits_succ.
+Qed.
+
+Lemma mul_pow2_bits : forall a n m, 0<=n -> (a*2^n).[m] = a.[m-n].
+Proof.
+ intros.
+ rewrite <- (add_simpl_r m n) at 1. rewrite add_sub_swap, add_comm.
+ now apply mul_pow2_bits_add.
+Qed.
+
+Lemma mul_pow2_bits_low : forall a n m, m<n -> (a*2^n).[m] = false.
+Proof.
+ intros.
+ destruct (le_gt_cases 0 n).
+ rewrite mul_pow2_bits by trivial.
+ apply testbit_neg_r. now apply lt_sub_0.
+ now rewrite pow_neg_r, mul_0_r, bits_0.
+Qed.
+
+(** Selecting the low part of a number can be done by a modulo *)
+
+Lemma mod_pow2_bits_high : forall a n m, 0<=n<=m ->
+ (a mod 2^n).[m] = false.
+Proof.
+ intros a n m (Hn,H).
+ destruct (mod_pos_bound a (2^n)) as [LE LT]. order_pos.
+ le_elim LE.
+ apply bits_above_log2; try order.
+ apply lt_le_trans with n; trivial.
+ apply log2_lt_pow2; trivial.
+ now rewrite <- LE, bits_0.
+Qed.
+
+Lemma mod_pow2_bits_low : forall a n m, m<n ->
+ (a mod 2^n).[m] = a.[m].
+Proof.
+ intros a n m H.
+ destruct (le_gt_cases 0 m) as [Hm|Hm]; [|now rewrite !testbit_neg_r].
+ rewrite testbit_eqb; trivial.
+ rewrite <- (mod_add _ (2^(P (n-m))*(a/2^n))) by order'.
+ rewrite <- div_add by order_nz.
+ rewrite (mul_comm _ 2), mul_assoc, <- pow_succ_r, succ_pred.
+ rewrite mul_comm, mul_assoc, <- pow_add_r, (add_comm m), sub_add; trivial.
+ rewrite add_comm, <- div_mod by order_nz.
+ symmetry. apply testbit_eqb; trivial.
+ apply le_0_sub; order.
+ now apply lt_le_pred, lt_0_sub.
+Qed.
+
+(** We now prove that having the same bits implies equality.
+ For that we use a notion of equality over functional
+ streams of bits. *)
+
+Definition eqf (f g:t -> bool) := forall n:t, f n = g n.
+
+Instance eqf_equiv : Equivalence eqf.
+Proof.
+ split; congruence.
+Qed.
+
+Local Infix "===" := eqf (at level 70, no associativity).
+
+Instance testbit_eqf : Proper (eq==>eqf) testbit.
+Proof.
+ intros a a' Ha n. now rewrite Ha.
+Qed.
+
+(** Only zero corresponds to the always-false stream. *)
+
+Lemma bits_inj_0 :
+ forall a, (forall n, a.[n] = false) -> a == 0.
+Proof.
+ intros a H. destruct (lt_trichotomy a 0) as [Ha|[Ha|Ha]]; trivial.
+ apply (bits_above_log2_neg a (S (log2 (P (-a))))) in Ha.
+ now rewrite H in Ha.
+ apply lt_succ_diag_r.
+ apply bit_log2 in Ha. now rewrite H in Ha.
+Qed.
+
+(** If two numbers produce the same stream of bits, they are equal. *)
+
+Lemma bits_inj : forall a b, testbit a === testbit b -> a == b.
+Proof.
+ assert (AUX : forall n, 0<=n -> forall a b,
+ 0<=a<2^n -> testbit a === testbit b -> a == b).
+ intros n Hn. apply le_ind with (4:=Hn).
+ solve_proper.
+ intros a b Ha H. rewrite pow_0_r, one_succ, lt_succ_r in Ha.
+ assert (Ha' : a == 0) by (destruct Ha; order).
+ rewrite Ha' in *.
+ symmetry. apply bits_inj_0.
+ intros m. now rewrite <- H, bits_0.
+ clear n Hn. intros n Hn IH a b (Ha,Ha') H.
+ rewrite (div_mod a 2), (div_mod b 2) by order'.
+ f_equiv; [ | now rewrite <- 2 bit0_mod, H].
+ f_equiv.
+ apply IH.
+ split. apply div_pos; order'.
+ apply div_lt_upper_bound. order'. now rewrite <- pow_succ_r.
+ intros m.
+ destruct (le_gt_cases 0 m).
+ rewrite 2 div2_bits by trivial. apply H.
+ now rewrite 2 testbit_neg_r.
+ intros a b H.
+ destruct (le_gt_cases 0 a) as [Ha|Ha].
+ apply (AUX a); trivial. split; trivial.
+ apply pow_gt_lin_r; order'.
+ apply succ_inj, opp_inj.
+ assert (0 <= - S a).
+ apply opp_le_mono. now rewrite opp_involutive, opp_0, le_succ_l.
+ apply (AUX (-(S a))); trivial. split; trivial.
+ apply pow_gt_lin_r; order'.
+ intros m. destruct (le_gt_cases 0 m).
+ now rewrite 2 bits_opp, 2 pred_succ, H.
+ now rewrite 2 testbit_neg_r.
+Qed.
+
+Lemma bits_inj_iff : forall a b, testbit a === testbit b <-> a == b.
+Proof.
+ split. apply bits_inj. intros EQ; now rewrite EQ.
+Qed.
+
+(** In fact, checking the bits at positive indexes is enough. *)
+
+Lemma bits_inj' : forall a b,
+ (forall n, 0<=n -> a.[n] = b.[n]) -> a == b.
+Proof.
+ intros a b H. apply bits_inj.
+ intros n. destruct (le_gt_cases 0 n).
+ now apply H.
+ now rewrite 2 testbit_neg_r.
+Qed.
+
+Lemma bits_inj_iff' : forall a b, (forall n, 0<=n -> a.[n] = b.[n]) <-> a == b.
+Proof.
+ split. apply bits_inj'. intros EQ n Hn; now rewrite EQ.
+Qed.
+
+Ltac bitwise := apply bits_inj'; intros ?m ?Hm; autorewrite with bitwise.
+
+Hint Rewrite lxor_spec lor_spec land_spec ldiff_spec bits_0 : bitwise.
+
+(** The streams of bits that correspond to a numbers are
+ exactly the ones which are stationary after some point. *)
+
+Lemma are_bits : forall (f:t->bool), Proper (eq==>Logic.eq) f ->
+ ((exists n, forall m, 0<=m -> f m = n.[m]) <->
+ (exists k, forall m, k<=m -> f m = f k)).
+Proof.
+ intros f Hf. split.
+ intros (a,H).
+ destruct (le_gt_cases 0 a).
+ exists (S (log2 a)). intros m Hm. apply le_succ_l in Hm.
+ rewrite 2 H, 2 bits_above_log2; trivial using lt_succ_diag_r.
+ order_pos. apply le_trans with (log2 a); order_pos.
+ exists (S (log2 (P (-a)))). intros m Hm. apply le_succ_l in Hm.
+ rewrite 2 H, 2 bits_above_log2_neg; trivial using lt_succ_diag_r.
+ order_pos. apply le_trans with (log2 (P (-a))); order_pos.
+ intros (k,Hk).
+ destruct (lt_ge_cases k 0) as [LT|LE].
+ case_eq (f 0); intros H0.
+ exists (-1). intros m Hm. rewrite bits_m1, Hk by order.
+ symmetry; rewrite <- H0. apply Hk; order.
+ exists 0. intros m Hm. rewrite bits_0, Hk by order.
+ symmetry; rewrite <- H0. apply Hk; order.
+ revert f Hf Hk. apply le_ind with (4:=LE).
+ (* compat : solve_proper fails here *)
+ apply proper_sym_impl_iff. exact eq_sym.
+ clear k LE. intros k k' Hk IH f Hf H. apply IH; trivial.
+ now setoid_rewrite Hk.
+ (* /compat *)
+ intros f Hf H0. destruct (f 0).
+ exists (-1). intros m Hm. now rewrite bits_m1, H0.
+ exists 0. intros m Hm. now rewrite bits_0, H0.
+ clear k LE. intros k LE IH f Hf Hk.
+ destruct (IH (fun m => f (S m))) as (n, Hn).
+ solve_proper.
+ intros m Hm. apply Hk. now rewrite <- succ_le_mono.
+ exists (f 0 + 2*n). intros m Hm.
+ le_elim Hm.
+ rewrite <- (succ_pred m), Hn, <- div2_bits.
+ rewrite mul_comm, div_add, b2z_div2, add_0_l; trivial. order'.
+ now rewrite <- lt_succ_r, succ_pred.
+ now rewrite <- lt_succ_r, succ_pred.
+ rewrite <- Hm.
+ symmetry. apply add_b2z_double_bit0.
+Qed.
+
+(** * Properties of shifts *)
+
+(** First, a unified specification for [shiftl] : the [shiftl_spec]
+ below (combined with [testbit_neg_r]) is equivalent to
+ [shiftl_spec_low] and [shiftl_spec_high]. *)
+
+Lemma shiftl_spec : forall a n m, 0<=m -> (a << n).[m] = a.[m-n].
+Proof.
+ intros.
+ destruct (le_gt_cases n m).
+ now apply shiftl_spec_high.
+ rewrite shiftl_spec_low, testbit_neg_r; trivial. now apply lt_sub_0.
+Qed.
+
+(** A shiftl by a negative number is a shiftr, and vice-versa *)
+
+Lemma shiftr_opp_r : forall a n, a >> (-n) == a << n.
+Proof.
+ intros. bitwise. now rewrite shiftr_spec, shiftl_spec, add_opp_r.
+Qed.
+
+Lemma shiftl_opp_r : forall a n, a << (-n) == a >> n.
+Proof.
+ intros. bitwise. now rewrite shiftr_spec, shiftl_spec, sub_opp_r.
+Qed.
+
+(** Shifts correspond to multiplication or division by a power of two *)
+
+Lemma shiftr_div_pow2 : forall a n, 0<=n -> a >> n == a / 2^n.
+Proof.
+ intros. bitwise. now rewrite shiftr_spec, div_pow2_bits.
+Qed.
+
+Lemma shiftr_mul_pow2 : forall a n, n<=0 -> a >> n == a * 2^(-n).
+Proof.
+ intros. bitwise. rewrite shiftr_spec, mul_pow2_bits; trivial.
+ now rewrite sub_opp_r.
+ now apply opp_nonneg_nonpos.
+Qed.
+
+Lemma shiftl_mul_pow2 : forall a n, 0<=n -> a << n == a * 2^n.
+Proof.
+ intros. bitwise. now rewrite shiftl_spec, mul_pow2_bits.
+Qed.
+
+Lemma shiftl_div_pow2 : forall a n, n<=0 -> a << n == a / 2^(-n).
+Proof.
+ intros. bitwise. rewrite shiftl_spec, div_pow2_bits; trivial.
+ now rewrite add_opp_r.
+ now apply opp_nonneg_nonpos.
+Qed.
+
+(** Shifts are morphisms *)
+
+Instance shiftr_wd : Proper (eq==>eq==>eq) shiftr.
+Proof.
+ intros a a' Ha n n' Hn.
+ destruct (le_ge_cases n 0) as [H|H]; assert (H':=H); rewrite Hn in H'.
+ now rewrite 2 shiftr_mul_pow2, Ha, Hn.
+ now rewrite 2 shiftr_div_pow2, Ha, Hn.
+Qed.
+
+Instance shiftl_wd : Proper (eq==>eq==>eq) shiftl.
+Proof.
+ intros a a' Ha n n' Hn. now rewrite <- 2 shiftr_opp_r, Ha, Hn.
+Qed.
+
+(** We could also have specified shiftl with an addition on the left. *)
+
+Lemma shiftl_spec_alt : forall a n m, 0<=n -> (a << n).[m+n] = a.[m].
+Proof.
+ intros. now rewrite shiftl_mul_pow2, mul_pow2_bits, add_simpl_r.
+Qed.
+
+(** Chaining several shifts. The only case for which
+ there isn't any simple expression is a true shiftr
+ followed by a true shiftl.
+*)
+
+Lemma shiftl_shiftl : forall a n m, 0<=n ->
+ (a << n) << m == a << (n+m).
+Proof.
+ intros a n p Hn. bitwise.
+ rewrite 2 (shiftl_spec _ _ m) by trivial.
+ rewrite add_comm, sub_add_distr.
+ destruct (le_gt_cases 0 (m-p)) as [H|H].
+ now rewrite shiftl_spec.
+ rewrite 2 testbit_neg_r; trivial.
+ apply lt_sub_0. now apply lt_le_trans with 0.
+Qed.
+
+Lemma shiftr_shiftl_l : forall a n m, 0<=n ->
+ (a << n) >> m == a << (n-m).
+Proof.
+ intros. now rewrite <- shiftl_opp_r, shiftl_shiftl, add_opp_r.
+Qed.
+
+Lemma shiftr_shiftl_r : forall a n m, 0<=n ->
+ (a << n) >> m == a >> (m-n).
+Proof.
+ intros. now rewrite <- 2 shiftl_opp_r, shiftl_shiftl, opp_sub_distr, add_comm.
+Qed.
+
+Lemma shiftr_shiftr : forall a n m, 0<=m ->
+ (a >> n) >> m == a >> (n+m).
+Proof.
+ intros a n p Hn. bitwise.
+ rewrite 3 shiftr_spec; trivial.
+ now rewrite (add_comm n p), add_assoc.
+ now apply add_nonneg_nonneg.
+Qed.
+
+(** shifts and constants *)
+
+Lemma shiftl_1_l : forall n, 1 << n == 2^n.
+Proof.
+ intros n. destruct (le_gt_cases 0 n).
+ now rewrite shiftl_mul_pow2, mul_1_l.
+ rewrite shiftl_div_pow2, div_1_l, pow_neg_r; try order.
+ apply pow_gt_1. order'. now apply opp_pos_neg.
+Qed.
+
+Lemma shiftl_0_r : forall a, a << 0 == a.
+Proof.
+ intros. rewrite shiftl_mul_pow2 by order. now nzsimpl.
+Qed.
+
+Lemma shiftr_0_r : forall a, a >> 0 == a.
+Proof.
+ intros. now rewrite <- shiftl_opp_r, opp_0, shiftl_0_r.
+Qed.
+
+Lemma shiftl_0_l : forall n, 0 << n == 0.
+Proof.
+ intros.
+ destruct (le_ge_cases 0 n).
+ rewrite shiftl_mul_pow2 by trivial. now nzsimpl.
+ rewrite shiftl_div_pow2 by trivial.
+ rewrite <- opp_nonneg_nonpos in H. nzsimpl; order_nz.
+Qed.
+
+Lemma shiftr_0_l : forall n, 0 >> n == 0.
+Proof.
+ intros. now rewrite <- shiftl_opp_r, shiftl_0_l.
+Qed.
+
+Lemma shiftl_eq_0_iff : forall a n, 0<=n -> (a << n == 0 <-> a == 0).
+Proof.
+ intros a n Hn.
+ rewrite shiftl_mul_pow2 by trivial. rewrite eq_mul_0. split.
+ intros [H | H]; trivial. contradict H; order_nz.
+ intros H. now left.
+Qed.
+
+Lemma shiftr_eq_0_iff : forall a n,
+ a >> n == 0 <-> a==0 \/ (0<a /\ log2 a < n).
+Proof.
+ intros a n.
+ destruct (le_gt_cases 0 n) as [Hn|Hn].
+ rewrite shiftr_div_pow2, div_small_iff by order_nz.
+ destruct (lt_trichotomy a 0) as [LT|[EQ|LT]].
+ split.
+ intros [(H,_)|(H,H')]. order. generalize (pow_nonneg 2 n le_0_2); order.
+ intros [H|(H,H')]; order.
+ rewrite EQ. split. now left. intros _; left. split; order_pos.
+ split. intros [(H,H')|(H,H')]; right. split; trivial.
+ apply log2_lt_pow2; trivial.
+ generalize (pow_nonneg 2 n le_0_2); order.
+ intros [H|(H,H')]. order. left.
+ split. order. now apply log2_lt_pow2.
+ rewrite shiftr_mul_pow2 by order. rewrite eq_mul_0.
+ split; intros [H|H].
+ now left.
+ elim (pow_nonzero 2 (-n)); try apply opp_nonneg_nonpos; order'.
+ now left.
+ destruct H. generalize (log2_nonneg a); order.
+Qed.
+
+Lemma shiftr_eq_0 : forall a n, 0<=a -> log2 a < n -> a >> n == 0.
+Proof.
+ intros a n Ha H. apply shiftr_eq_0_iff.
+ le_elim Ha. right. now split. now left.
+Qed.
+
+(** Properties of [div2]. *)
+
+Lemma div2_div : forall a, div2 a == a/2.
+Proof.
+ intros. rewrite div2_spec, shiftr_div_pow2. now nzsimpl. order'.
+Qed.
+
+Instance div2_wd : Proper (eq==>eq) div2.
+Proof.
+ intros a a' Ha. now rewrite 2 div2_div, Ha.
+Qed.
+
+Lemma div2_odd : forall a, a == 2*(div2 a) + odd a.
+Proof.
+ intros a. rewrite div2_div, <- bit0_odd, bit0_mod.
+ apply div_mod. order'.
+Qed.
+
+(** Properties of [lxor] and others, directly deduced
+ from properties of [xorb] and others. *)
+
+Instance lxor_wd : Proper (eq ==> eq ==> eq) lxor.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Instance land_wd : Proper (eq ==> eq ==> eq) land.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Instance lor_wd : Proper (eq ==> eq ==> eq) lor.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Instance ldiff_wd : Proper (eq ==> eq ==> eq) ldiff.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Lemma lxor_eq : forall a a', lxor a a' == 0 -> a == a'.
+Proof.
+ intros a a' H. bitwise. apply xorb_eq.
+ now rewrite <- lxor_spec, H, bits_0.
+Qed.
+
+Lemma lxor_nilpotent : forall a, lxor a a == 0.
+Proof.
+ intros. bitwise. apply xorb_nilpotent.
+Qed.
+
+Lemma lxor_eq_0_iff : forall a a', lxor a a' == 0 <-> a == a'.
+Proof.
+ split. apply lxor_eq. intros EQ; rewrite EQ; apply lxor_nilpotent.
+Qed.
+
+Lemma lxor_0_l : forall a, lxor 0 a == a.
+Proof.
+ intros. bitwise. apply xorb_false_l.
+Qed.
+
+Lemma lxor_0_r : forall a, lxor a 0 == a.
+Proof.
+ intros. bitwise. apply xorb_false_r.
+Qed.
+
+Lemma lxor_comm : forall a b, lxor a b == lxor b a.
+Proof.
+ intros. bitwise. apply xorb_comm.
+Qed.
+
+Lemma lxor_assoc :
+ forall a b c, lxor (lxor a b) c == lxor a (lxor b c).
+Proof.
+ intros. bitwise. apply xorb_assoc.
+Qed.
+
+Lemma lor_0_l : forall a, lor 0 a == a.
+Proof.
+ intros. bitwise. trivial.
+Qed.
+
+Lemma lor_0_r : forall a, lor a 0 == a.
+Proof.
+ intros. bitwise. apply orb_false_r.
+Qed.
+
+Lemma lor_comm : forall a b, lor a b == lor b a.
+Proof.
+ intros. bitwise. apply orb_comm.
+Qed.
+
+Lemma lor_assoc :
+ forall a b c, lor a (lor b c) == lor (lor a b) c.
+Proof.
+ intros. bitwise. apply orb_assoc.
+Qed.
+
+Lemma lor_diag : forall a, lor a a == a.
+Proof.
+ intros. bitwise. apply orb_diag.
+Qed.
+
+Lemma lor_eq_0_l : forall a b, lor a b == 0 -> a == 0.
+Proof.
+ intros a b H. bitwise.
+ apply (orb_false_iff a.[m] b.[m]).
+ now rewrite <- lor_spec, H, bits_0.
+Qed.
+
+Lemma lor_eq_0_iff : forall a b, lor a b == 0 <-> a == 0 /\ b == 0.
+Proof.
+ intros a b. split.
+ split. now apply lor_eq_0_l in H.
+ rewrite lor_comm in H. now apply lor_eq_0_l in H.
+ intros (EQ,EQ'). now rewrite EQ, lor_0_l.
+Qed.
+
+Lemma land_0_l : forall a, land 0 a == 0.
+Proof.
+ intros. bitwise. trivial.
+Qed.
+
+Lemma land_0_r : forall a, land a 0 == 0.
+Proof.
+ intros. bitwise. apply andb_false_r.
+Qed.
+
+Lemma land_comm : forall a b, land a b == land b a.
+Proof.
+ intros. bitwise. apply andb_comm.
+Qed.
+
+Lemma land_assoc :
+ forall a b c, land a (land b c) == land (land a b) c.
+Proof.
+ intros. bitwise. apply andb_assoc.
+Qed.
+
+Lemma land_diag : forall a, land a a == a.
+Proof.
+ intros. bitwise. apply andb_diag.
+Qed.
+
+Lemma ldiff_0_l : forall a, ldiff 0 a == 0.
+Proof.
+ intros. bitwise. trivial.
+Qed.
+
+Lemma ldiff_0_r : forall a, ldiff a 0 == a.
+Proof.
+ intros. bitwise. now rewrite andb_true_r.
+Qed.
+
+Lemma ldiff_diag : forall a, ldiff a a == 0.
+Proof.
+ intros. bitwise. apply andb_negb_r.
+Qed.
+
+Lemma lor_land_distr_l : forall a b c,
+ lor (land a b) c == land (lor a c) (lor b c).
+Proof.
+ intros. bitwise. apply orb_andb_distrib_l.
+Qed.
+
+Lemma lor_land_distr_r : forall a b c,
+ lor a (land b c) == land (lor a b) (lor a c).
+Proof.
+ intros. bitwise. apply orb_andb_distrib_r.
+Qed.
+
+Lemma land_lor_distr_l : forall a b c,
+ land (lor a b) c == lor (land a c) (land b c).
+Proof.
+ intros. bitwise. apply andb_orb_distrib_l.
+Qed.
+
+Lemma land_lor_distr_r : forall a b c,
+ land a (lor b c) == lor (land a b) (land a c).
+Proof.
+ intros. bitwise. apply andb_orb_distrib_r.
+Qed.
+
+Lemma ldiff_ldiff_l : forall a b c,
+ ldiff (ldiff a b) c == ldiff a (lor b c).
+Proof.
+ intros. bitwise. now rewrite negb_orb, andb_assoc.
+Qed.
+
+Lemma lor_ldiff_and : forall a b,
+ lor (ldiff a b) (land a b) == a.
+Proof.
+ intros. bitwise.
+ now rewrite <- andb_orb_distrib_r, orb_comm, orb_negb_r, andb_true_r.
+Qed.
+
+Lemma land_ldiff : forall a b,
+ land (ldiff a b) b == 0.
+Proof.
+ intros. bitwise.
+ now rewrite <-andb_assoc, (andb_comm (negb _)), andb_negb_r, andb_false_r.
+Qed.
+
+(** Properties of [setbit] and [clearbit] *)
+
+Definition setbit a n := lor a (1 << n).
+Definition clearbit a n := ldiff a (1 << n).
+
+Lemma setbit_spec' : forall a n, setbit a n == lor a (2^n).
+Proof.
+ intros. unfold setbit. now rewrite shiftl_1_l.
+Qed.
+
+Lemma clearbit_spec' : forall a n, clearbit a n == ldiff a (2^n).
+Proof.
+ intros. unfold clearbit. now rewrite shiftl_1_l.
+Qed.
+
+Instance setbit_wd : Proper (eq==>eq==>eq) setbit.
+Proof. unfold setbit. solve_proper. Qed.
+
+Instance clearbit_wd : Proper (eq==>eq==>eq) clearbit.
+Proof. unfold clearbit. solve_proper. Qed.
+
+Lemma pow2_bits_true : forall n, 0<=n -> (2^n).[n] = true.
+Proof.
+ intros. rewrite <- (mul_1_l (2^n)).
+ now rewrite mul_pow2_bits, sub_diag, bit0_odd, odd_1.
+Qed.
+
+Lemma pow2_bits_false : forall n m, n~=m -> (2^n).[m] = false.
+Proof.
+ intros.
+ destruct (le_gt_cases 0 n); [|now rewrite pow_neg_r, bits_0].
+ destruct (le_gt_cases n m).
+ rewrite <- (mul_1_l (2^n)), mul_pow2_bits; trivial.
+ rewrite <- (succ_pred (m-n)), <- div2_bits.
+ now rewrite div_small, bits_0 by (split; order').
+ rewrite <- lt_succ_r, succ_pred, lt_0_sub. order.
+ rewrite <- (mul_1_l (2^n)), mul_pow2_bits_low; trivial.
+Qed.
+
+Lemma pow2_bits_eqb : forall n m, 0<=n -> (2^n).[m] = eqb n m.
+Proof.
+ intros n m Hn. apply eq_true_iff_eq. rewrite eqb_eq. split.
+ destruct (eq_decidable n m) as [H|H]. trivial.
+ now rewrite (pow2_bits_false _ _ H).
+ intros EQ. rewrite EQ. apply pow2_bits_true; order.
+Qed.
+
+Lemma setbit_eqb : forall a n m, 0<=n ->
+ (setbit a n).[m] = eqb n m || a.[m].
+Proof.
+ intros. now rewrite setbit_spec', lor_spec, pow2_bits_eqb, orb_comm.
+Qed.
+
+Lemma setbit_iff : forall a n m, 0<=n ->
+ ((setbit a n).[m] = true <-> n==m \/ a.[m] = true).
+Proof.
+ intros. now rewrite setbit_eqb, orb_true_iff, eqb_eq.
+Qed.
+
+Lemma setbit_eq : forall a n, 0<=n -> (setbit a n).[n] = true.
+Proof.
+ intros. apply setbit_iff; trivial. now left.
+Qed.
+
+Lemma setbit_neq : forall a n m, 0<=n -> n~=m ->
+ (setbit a n).[m] = a.[m].
+Proof.
+ intros a n m Hn H. rewrite setbit_eqb; trivial.
+ rewrite <- eqb_eq in H. apply not_true_is_false in H. now rewrite H.
+Qed.
+
+Lemma clearbit_eqb : forall a n m,
+ (clearbit a n).[m] = a.[m] && negb (eqb n m).
+Proof.
+ intros.
+ destruct (le_gt_cases 0 m); [| now rewrite 2 testbit_neg_r].
+ rewrite clearbit_spec', ldiff_spec. f_equal. f_equal.
+ destruct (le_gt_cases 0 n) as [Hn|Hn].
+ now apply pow2_bits_eqb.
+ symmetry. rewrite pow_neg_r, bits_0, <- not_true_iff_false, eqb_eq; order.
+Qed.
+
+Lemma clearbit_iff : forall a n m,
+ (clearbit a n).[m] = true <-> a.[m] = true /\ n~=m.
+Proof.
+ intros. rewrite clearbit_eqb, andb_true_iff, <- eqb_eq.
+ now rewrite negb_true_iff, not_true_iff_false.
+Qed.
+
+Lemma clearbit_eq : forall a n, (clearbit a n).[n] = false.
+Proof.
+ intros. rewrite clearbit_eqb, (proj2 (eqb_eq _ _) (eq_refl n)).
+ apply andb_false_r.
+Qed.
+
+Lemma clearbit_neq : forall a n m, n~=m ->
+ (clearbit a n).[m] = a.[m].
+Proof.
+ intros a n m H. rewrite clearbit_eqb.
+ rewrite <- eqb_eq in H. apply not_true_is_false in H. rewrite H.
+ apply andb_true_r.
+Qed.
+
+(** Shifts of bitwise operations *)
+
+Lemma shiftl_lxor : forall a b n,
+ (lxor a b) << n == lxor (a << n) (b << n).
+Proof.
+ intros. bitwise. now rewrite !shiftl_spec, lxor_spec.
+Qed.
+
+Lemma shiftr_lxor : forall a b n,
+ (lxor a b) >> n == lxor (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec, lxor_spec.
+Qed.
+
+Lemma shiftl_land : forall a b n,
+ (land a b) << n == land (a << n) (b << n).
+Proof.
+ intros. bitwise. now rewrite !shiftl_spec, land_spec.
+Qed.
+
+Lemma shiftr_land : forall a b n,
+ (land a b) >> n == land (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec, land_spec.
+Qed.
+
+Lemma shiftl_lor : forall a b n,
+ (lor a b) << n == lor (a << n) (b << n).
+Proof.
+ intros. bitwise. now rewrite !shiftl_spec, lor_spec.
+Qed.
+
+Lemma shiftr_lor : forall a b n,
+ (lor a b) >> n == lor (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec, lor_spec.
+Qed.
+
+Lemma shiftl_ldiff : forall a b n,
+ (ldiff a b) << n == ldiff (a << n) (b << n).
+Proof.
+ intros. bitwise. now rewrite !shiftl_spec, ldiff_spec.
+Qed.
+
+Lemma shiftr_ldiff : forall a b n,
+ (ldiff a b) >> n == ldiff (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec, ldiff_spec.
+Qed.
+
+(** For integers, we do have a binary complement function *)
+
+Definition lnot a := P (-a).
+
+Instance lnot_wd : Proper (eq==>eq) lnot.
+Proof. unfold lnot. solve_proper. Qed.
+
+Lemma lnot_spec : forall a n, 0<=n -> (lnot a).[n] = negb a.[n].
+Proof.
+ intros. unfold lnot. rewrite <- (opp_involutive a) at 2.
+ rewrite bits_opp, negb_involutive; trivial.
+Qed.
+
+Lemma lnot_involutive : forall a, lnot (lnot a) == a.
+Proof.
+ intros a. bitwise. now rewrite 2 lnot_spec, negb_involutive.
+Qed.
+
+Lemma lnot_0 : lnot 0 == -1.
+Proof.
+ unfold lnot. now rewrite opp_0, <- sub_1_r, sub_0_l.
+Qed.
+
+Lemma lnot_m1 : lnot (-1) == 0.
+Proof.
+ unfold lnot. now rewrite opp_involutive, one_succ, pred_succ.
+Qed.
+
+(** Complement and other operations *)
+
+Lemma lor_m1_r : forall a, lor a (-1) == -1.
+Proof.
+ intros. bitwise. now rewrite bits_m1, orb_true_r.
+Qed.
+
+Lemma lor_m1_l : forall a, lor (-1) a == -1.
+Proof.
+ intros. now rewrite lor_comm, lor_m1_r.
+Qed.
+
+Lemma land_m1_r : forall a, land a (-1) == a.
+Proof.
+ intros. bitwise. now rewrite bits_m1, andb_true_r.
+Qed.
+
+Lemma land_m1_l : forall a, land (-1) a == a.
+Proof.
+ intros. now rewrite land_comm, land_m1_r.
+Qed.
+
+Lemma ldiff_m1_r : forall a, ldiff a (-1) == 0.
+Proof.
+ intros. bitwise. now rewrite bits_m1, andb_false_r.
+Qed.
+
+Lemma ldiff_m1_l : forall a, ldiff (-1) a == lnot a.
+Proof.
+ intros. bitwise. now rewrite lnot_spec, bits_m1.
+Qed.
+
+Lemma lor_lnot_diag : forall a, lor a (lnot a) == -1.
+Proof.
+ intros a. bitwise. rewrite lnot_spec, bits_m1; trivial.
+ now destruct a.[m].
+Qed.
+
+Lemma add_lnot_diag : forall a, a + lnot a == -1.
+Proof.
+ intros a. unfold lnot.
+ now rewrite add_pred_r, add_opp_r, sub_diag, one_succ, opp_succ, opp_0.
+Qed.
+
+Lemma ldiff_land : forall a b, ldiff a b == land a (lnot b).
+Proof.
+ intros. bitwise. now rewrite lnot_spec.
+Qed.
+
+Lemma land_lnot_diag : forall a, land a (lnot a) == 0.
+Proof.
+ intros. now rewrite <- ldiff_land, ldiff_diag.
+Qed.
+
+Lemma lnot_lor : forall a b, lnot (lor a b) == land (lnot a) (lnot b).
+Proof.
+ intros a b. bitwise. now rewrite !lnot_spec, lor_spec, negb_orb.
+Qed.
+
+Lemma lnot_land : forall a b, lnot (land a b) == lor (lnot a) (lnot b).
+Proof.
+ intros a b. bitwise. now rewrite !lnot_spec, land_spec, negb_andb.
+Qed.
+
+Lemma lnot_ldiff : forall a b, lnot (ldiff a b) == lor (lnot a) b.
+Proof.
+ intros a b. bitwise.
+ now rewrite !lnot_spec, ldiff_spec, negb_andb, negb_involutive.
+Qed.
+
+Lemma lxor_lnot_lnot : forall a b, lxor (lnot a) (lnot b) == lxor a b.
+Proof.
+ intros a b. bitwise. now rewrite !lnot_spec, xorb_negb_negb.
+Qed.
+
+Lemma lnot_lxor_l : forall a b, lnot (lxor a b) == lxor (lnot a) b.
+Proof.
+ intros a b. bitwise. now rewrite !lnot_spec, !lxor_spec, negb_xorb_l.
+Qed.
+
+Lemma lnot_lxor_r : forall a b, lnot (lxor a b) == lxor a (lnot b).
+Proof.
+ intros a b. bitwise. now rewrite !lnot_spec, !lxor_spec, negb_xorb_r.
+Qed.
+
+Lemma lxor_m1_r : forall a, lxor a (-1) == lnot a.
+Proof.
+ intros. now rewrite <- (lxor_0_r (lnot a)), <- lnot_m1, lxor_lnot_lnot.
+Qed.
+
+Lemma lxor_m1_l : forall a, lxor (-1) a == lnot a.
+Proof.
+ intros. now rewrite lxor_comm, lxor_m1_r.
+Qed.
+
+Lemma lxor_lor : forall a b, land a b == 0 ->
+ lxor a b == lor a b.
+Proof.
+ intros a b H. bitwise.
+ assert (a.[m] && b.[m] = false)
+ by now rewrite <- land_spec, H, bits_0.
+ now destruct a.[m], b.[m].
+Qed.
+
+Lemma lnot_shiftr : forall a n, 0<=n -> lnot (a >> n) == (lnot a) >> n.
+Proof.
+ intros a n Hn. bitwise.
+ now rewrite lnot_spec, 2 shiftr_spec, lnot_spec by order_pos.
+Qed.
+
+(** [(ones n)] is [2^n-1], the number with [n] digits 1 *)
+
+Definition ones n := P (1<<n).
+
+Instance ones_wd : Proper (eq==>eq) ones.
+Proof. unfold ones. solve_proper. Qed.
+
+Lemma ones_equiv : forall n, ones n == P (2^n).
+Proof.
+ intros. unfold ones.
+ destruct (le_gt_cases 0 n).
+ now rewrite shiftl_mul_pow2, mul_1_l.
+ f_equiv. rewrite pow_neg_r; trivial.
+ rewrite <- shiftr_opp_r. apply shiftr_eq_0_iff. right; split.
+ order'. rewrite log2_1. now apply opp_pos_neg.
+Qed.
+
+Lemma ones_add : forall n m, 0<=n -> 0<=m ->
+ ones (m+n) == 2^m * ones n + ones m.
+Proof.
+ intros n m Hn Hm. rewrite !ones_equiv.
+ rewrite <- !sub_1_r, mul_sub_distr_l, mul_1_r, <- pow_add_r by trivial.
+ rewrite add_sub_assoc, sub_add. reflexivity.
+Qed.
+
+Lemma ones_div_pow2 : forall n m, 0<=m<=n -> ones n / 2^m == ones (n-m).
+Proof.
+ intros n m (Hm,H). symmetry. apply div_unique with (ones m).
+ left. rewrite ones_equiv. split.
+ rewrite <- lt_succ_r, succ_pred. order_pos.
+ now rewrite <- le_succ_l, succ_pred.
+ rewrite <- (sub_add m n) at 1. rewrite (add_comm _ m).
+ apply ones_add; trivial. now apply le_0_sub.
+Qed.
+
+Lemma ones_mod_pow2 : forall n m, 0<=m<=n -> (ones n) mod (2^m) == ones m.
+Proof.
+ intros n m (Hm,H). symmetry. apply mod_unique with (ones (n-m)).
+ left. rewrite ones_equiv. split.
+ rewrite <- lt_succ_r, succ_pred. order_pos.
+ now rewrite <- le_succ_l, succ_pred.
+ rewrite <- (sub_add m n) at 1. rewrite (add_comm _ m).
+ apply ones_add; trivial. now apply le_0_sub.
+Qed.
+
+Lemma ones_spec_low : forall n m, 0<=m<n -> (ones n).[m] = true.
+Proof.
+ intros n m (Hm,H). apply testbit_true; trivial.
+ rewrite ones_div_pow2 by (split; order).
+ rewrite <- (pow_1_r 2). rewrite ones_mod_pow2.
+ rewrite ones_equiv. now nzsimpl'.
+ split. order'. apply le_add_le_sub_r. nzsimpl. now apply le_succ_l.
+Qed.
+
+Lemma ones_spec_high : forall n m, 0<=n<=m -> (ones n).[m] = false.
+Proof.
+ intros n m (Hn,H). le_elim Hn.
+ apply bits_above_log2; rewrite ones_equiv.
+ rewrite <-lt_succ_r, succ_pred; order_pos.
+ rewrite log2_pred_pow2; trivial. now rewrite <-le_succ_l, succ_pred.
+ rewrite ones_equiv. now rewrite <- Hn, pow_0_r, one_succ, pred_succ, bits_0.
+Qed.
+
+Lemma ones_spec_iff : forall n m, 0<=n ->
+ ((ones n).[m] = true <-> 0<=m<n).
+Proof.
+ intros n m Hn. split. intros H.
+ destruct (lt_ge_cases m 0) as [Hm|Hm].
+ now rewrite testbit_neg_r in H.
+ split; trivial. apply lt_nge. intro H'. rewrite ones_spec_high in H.
+ discriminate. now split.
+ apply ones_spec_low.
+Qed.
+
+Lemma lor_ones_low : forall a n, 0<=a -> log2 a < n ->
+ lor a (ones n) == ones n.
+Proof.
+ intros a n Ha H. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, bits_above_log2; try split; trivial.
+ now apply lt_le_trans with n.
+ apply le_trans with (log2 a); order_pos.
+ rewrite ones_spec_low, orb_true_r; try split; trivial.
+Qed.
+
+Lemma land_ones : forall a n, 0<=n -> land a (ones n) == a mod 2^n.
+Proof.
+ intros a n Hn. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, mod_pow2_bits_high, andb_false_r;
+ try split; trivial.
+ rewrite ones_spec_low, mod_pow2_bits_low, andb_true_r;
+ try split; trivial.
+Qed.
+
+Lemma land_ones_low : forall a n, 0<=a -> log2 a < n ->
+ land a (ones n) == a.
+Proof.
+ intros a n Ha H.
+ assert (Hn : 0<=n) by (generalize (log2_nonneg a); order).
+ rewrite land_ones; trivial. apply mod_small.
+ split; trivial.
+ apply log2_lt_cancel. now rewrite log2_pow2.
+Qed.
+
+Lemma ldiff_ones_r : forall a n, 0<=n ->
+ ldiff a (ones n) == (a >> n) << n.
+Proof.
+ intros a n Hn. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, shiftl_spec_high, shiftr_spec; trivial.
+ rewrite sub_add; trivial. apply andb_true_r.
+ now apply le_0_sub.
+ now split.
+ rewrite ones_spec_low, shiftl_spec_low, andb_false_r;
+ try split; trivial.
+Qed.
+
+Lemma ldiff_ones_r_low : forall a n, 0<=a -> log2 a < n ->
+ ldiff a (ones n) == 0.
+Proof.
+ intros a n Ha H. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ split; trivial. now apply le_trans with (log2 a); order_pos.
+ rewrite ones_spec_low, andb_false_r; try split; trivial.
+Qed.
+
+Lemma ldiff_ones_l_low : forall a n, 0<=a -> log2 a < n ->
+ ldiff (ones n) a == lxor a (ones n).
+Proof.
+ intros a n Ha H. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ split; trivial. now apply le_trans with (log2 a); order_pos.
+ rewrite ones_spec_low, xorb_true_r; try split; trivial.
+Qed.
+
+(** Bitwise operations and sign *)
+
+Lemma shiftl_nonneg : forall a n, 0 <= (a << n) <-> 0 <= a.
+Proof.
+ intros a n.
+ destruct (le_ge_cases 0 n) as [Hn|Hn].
+ (* 0<=n *)
+ rewrite 2 bits_iff_nonneg_ex. split; intros (k,Hk).
+ exists (k-n). intros m Hm.
+ destruct (le_gt_cases 0 m); [|now rewrite testbit_neg_r].
+ rewrite <- (add_simpl_r m n), <- (shiftl_spec a n) by order_pos.
+ apply Hk. now apply lt_sub_lt_add_r.
+ exists (k+n). intros m Hm.
+ destruct (le_gt_cases 0 m); [|now rewrite testbit_neg_r].
+ rewrite shiftl_spec by trivial. apply Hk. now apply lt_add_lt_sub_r.
+ (* n<=0*)
+ rewrite <- shiftr_opp_r, 2 bits_iff_nonneg_ex. split; intros (k,Hk).
+ destruct (le_gt_cases 0 k).
+ exists (k-n). intros m Hm. apply lt_sub_lt_add_r in Hm.
+ rewrite <- (add_simpl_r m n), <- add_opp_r, <- (shiftr_spec a (-n)).
+ now apply Hk. order.
+ assert (EQ : a >> (-n) == 0).
+ apply bits_inj'. intros m Hm. rewrite bits_0. apply Hk; order.
+ apply shiftr_eq_0_iff in EQ.
+ rewrite <- bits_iff_nonneg_ex. destruct EQ as [EQ|[LT _]]; order.
+ exists (k+n). intros m Hm.
+ destruct (le_gt_cases 0 m); [|now rewrite testbit_neg_r].
+ rewrite shiftr_spec by trivial. apply Hk.
+ rewrite add_opp_r. now apply lt_add_lt_sub_r.
+Qed.
+
+Lemma shiftl_neg : forall a n, (a << n) < 0 <-> a < 0.
+Proof.
+ intros a n. now rewrite 2 lt_nge, shiftl_nonneg.
+Qed.
+
+Lemma shiftr_nonneg : forall a n, 0 <= (a >> n) <-> 0 <= a.
+Proof.
+ intros. rewrite <- shiftl_opp_r. apply shiftl_nonneg.
+Qed.
+
+Lemma shiftr_neg : forall a n, (a >> n) < 0 <-> a < 0.
+Proof.
+ intros a n. now rewrite 2 lt_nge, shiftr_nonneg.
+Qed.
+
+Lemma div2_nonneg : forall a, 0 <= div2 a <-> 0 <= a.
+Proof.
+ intros. rewrite div2_spec. apply shiftr_nonneg.
+Qed.
+
+Lemma div2_neg : forall a, div2 a < 0 <-> a < 0.
+Proof.
+ intros a. now rewrite 2 lt_nge, div2_nonneg.
+Qed.
+
+Lemma lor_nonneg : forall a b, 0 <= lor a b <-> 0<=a /\ 0<=b.
+Proof.
+ intros a b.
+ rewrite 3 bits_iff_nonneg_ex. split. intros (k,Hk).
+ split; exists k; intros m Hm; apply (orb_false_elim a.[m] b.[m]);
+ rewrite <- lor_spec; now apply Hk.
+ intros ((k,Hk),(k',Hk')).
+ destruct (le_ge_cases k k'); [ exists k' | exists k ];
+ intros m Hm; rewrite lor_spec, Hk, Hk'; trivial; order.
+Qed.
+
+Lemma lor_neg : forall a b, lor a b < 0 <-> a < 0 \/ b < 0.
+Proof.
+ intros a b. rewrite 3 lt_nge, lor_nonneg. split.
+ apply not_and. apply le_decidable.
+ now intros [H|H] (H',H'').
+Qed.
+
+Lemma lnot_nonneg : forall a, 0 <= lnot a <-> a < 0.
+Proof.
+ intros a; unfold lnot.
+ now rewrite <- opp_succ, opp_nonneg_nonpos, le_succ_l.
+Qed.
+
+Lemma lnot_neg : forall a, lnot a < 0 <-> 0 <= a.
+Proof.
+ intros a. now rewrite le_ngt, lt_nge, lnot_nonneg.
+Qed.
+
+Lemma land_nonneg : forall a b, 0 <= land a b <-> 0<=a \/ 0<=b.
+Proof.
+ intros a b.
+ now rewrite <- (lnot_involutive (land a b)), lnot_land, lnot_nonneg,
+ lor_neg, !lnot_neg.
+Qed.
+
+Lemma land_neg : forall a b, land a b < 0 <-> a < 0 /\ b < 0.
+Proof.
+ intros a b.
+ now rewrite <- (lnot_involutive (land a b)), lnot_land, lnot_neg,
+ lor_nonneg, !lnot_nonneg.
+Qed.
+
+Lemma ldiff_nonneg : forall a b, 0 <= ldiff a b <-> 0<=a \/ b<0.
+Proof.
+ intros. now rewrite ldiff_land, land_nonneg, lnot_nonneg.
+Qed.
+
+Lemma ldiff_neg : forall a b, ldiff a b < 0 <-> a<0 /\ 0<=b.
+Proof.
+ intros. now rewrite ldiff_land, land_neg, lnot_neg.
+Qed.
+
+Lemma lxor_nonneg : forall a b, 0 <= lxor a b <-> (0<=a <-> 0<=b).
+Proof.
+ assert (H : forall a b, 0<=a -> 0<=b -> 0<=lxor a b).
+ intros a b. rewrite 3 bits_iff_nonneg_ex. intros (k,Hk) (k', Hk').
+ destruct (le_ge_cases k k'); [ exists k' | exists k];
+ intros m Hm; rewrite lxor_spec, Hk, Hk'; trivial; order.
+ assert (H' : forall a b, 0<=a -> b<0 -> lxor a b<0).
+ intros a b. rewrite bits_iff_nonneg_ex, 2 bits_iff_neg_ex.
+ intros (k,Hk) (k', Hk').
+ destruct (le_ge_cases k k'); [ exists k' | exists k];
+ intros m Hm; rewrite lxor_spec, Hk, Hk'; trivial; order.
+ intros a b.
+ split.
+ intros Hab. split.
+ intros Ha. destruct (le_gt_cases 0 b) as [Hb|Hb]; trivial.
+ generalize (H' _ _ Ha Hb). order.
+ intros Hb. destruct (le_gt_cases 0 a) as [Ha|Ha]; trivial.
+ generalize (H' _ _ Hb Ha). rewrite lxor_comm. order.
+ intros E.
+ destruct (le_gt_cases 0 a) as [Ha|Ha]. apply H; trivial. apply E; trivial.
+ destruct (le_gt_cases 0 b) as [Hb|Hb]. apply H; trivial. apply E; trivial.
+ rewrite <- lxor_lnot_lnot. apply H; now apply lnot_nonneg.
+Qed.
+
+(** Bitwise operations and log2 *)
+
+Lemma log2_bits_unique : forall a n,
+ a.[n] = true ->
+ (forall m, n<m -> a.[m] = false) ->
+ log2 a == n.
+Proof.
+ intros a n H H'.
+ destruct (lt_trichotomy a 0) as [Ha|[Ha|Ha]].
+ (* a < 0 *)
+ destruct (proj1 (bits_iff_neg_ex a) Ha) as (k,Hk).
+ destruct (le_gt_cases n k).
+ specialize (Hk (S k) (lt_succ_diag_r _)).
+ rewrite H' in Hk. discriminate. apply lt_succ_r; order.
+ specialize (H' (S n) (lt_succ_diag_r _)).
+ rewrite Hk in H'. discriminate. apply lt_succ_r; order.
+ (* a = 0 *)
+ now rewrite Ha, bits_0 in H.
+ (* 0 < a *)
+ apply le_antisymm; apply le_ngt; intros LT.
+ specialize (H' _ LT). now rewrite bit_log2 in H'.
+ now rewrite bits_above_log2 in H by order.
+Qed.
+
+Lemma log2_shiftr : forall a n, 0<a -> log2 (a >> n) == max 0 (log2 a - n).
+Proof.
+ intros a n Ha.
+ destruct (le_gt_cases 0 (log2 a - n));
+ [rewrite max_r | rewrite max_l]; try order.
+ apply log2_bits_unique.
+ now rewrite shiftr_spec, sub_add, bit_log2.
+ intros m Hm.
+ destruct (le_gt_cases 0 m); [|now rewrite testbit_neg_r].
+ rewrite shiftr_spec; trivial. apply bits_above_log2; try order.
+ now apply lt_sub_lt_add_r.
+ rewrite lt_sub_lt_add_r, add_0_l in H.
+ apply log2_nonpos. apply le_lteq; right.
+ apply shiftr_eq_0_iff. right. now split.
+Qed.
+
+Lemma log2_shiftl : forall a n, 0<a -> 0<=n -> log2 (a << n) == log2 a + n.
+Proof.
+ intros a n Ha Hn.
+ rewrite shiftl_mul_pow2, add_comm by trivial.
+ now apply log2_mul_pow2.
+Qed.
+
+Lemma log2_shiftl' : forall a n, 0<a -> log2 (a << n) == max 0 (log2 a + n).
+Proof.
+ intros a n Ha.
+ rewrite <- shiftr_opp_r, log2_shiftr by trivial.
+ destruct (le_gt_cases 0 (log2 a + n));
+ [rewrite 2 max_r | rewrite 2 max_l]; rewrite ?sub_opp_r; try order.
+Qed.
+
+Lemma log2_lor : forall a b, 0<=a -> 0<=b ->
+ log2 (lor a b) == max (log2 a) (log2 b).
+Proof.
+ assert (AUX : forall a b, 0<=a -> a<=b -> log2 (lor a b) == log2 b).
+ intros a b Ha H.
+ le_elim Ha; [|now rewrite <- Ha, lor_0_l].
+ apply log2_bits_unique.
+ now rewrite lor_spec, bit_log2, orb_true_r by order.
+ intros m Hm. assert (H' := log2_le_mono _ _ H).
+ now rewrite lor_spec, 2 bits_above_log2 by order.
+ (* main *)
+ intros a b Ha Hb. destruct (le_ge_cases a b) as [H|H].
+ rewrite max_r by now apply log2_le_mono.
+ now apply AUX.
+ rewrite max_l by now apply log2_le_mono.
+ rewrite lor_comm. now apply AUX.
+Qed.
+
+Lemma log2_land : forall a b, 0<=a -> 0<=b ->
+ log2 (land a b) <= min (log2 a) (log2 b).
+Proof.
+ assert (AUX : forall a b, 0<=a -> a<=b -> log2 (land a b) <= log2 a).
+ intros a b Ha Hb.
+ apply le_ngt. intros LT.
+ assert (H : 0 <= land a b) by (apply land_nonneg; now left).
+ le_elim H.
+ generalize (bit_log2 (land a b) H).
+ now rewrite land_spec, bits_above_log2.
+ rewrite <- H in LT. apply log2_lt_cancel in LT; order.
+ (* main *)
+ intros a b Ha Hb.
+ destruct (le_ge_cases a b) as [H|H].
+ rewrite min_l by now apply log2_le_mono. now apply AUX.
+ rewrite min_r by now apply log2_le_mono. rewrite land_comm. now apply AUX.
+Qed.
+
+Lemma log2_lxor : forall a b, 0<=a -> 0<=b ->
+ log2 (lxor a b) <= max (log2 a) (log2 b).
+Proof.
+ assert (AUX : forall a b, 0<=a -> a<=b -> log2 (lxor a b) <= log2 b).
+ intros a b Ha Hb.
+ apply le_ngt. intros LT.
+ assert (H : 0 <= lxor a b) by (apply lxor_nonneg; split; order).
+ le_elim H.
+ generalize (bit_log2 (lxor a b) H).
+ rewrite lxor_spec, 2 bits_above_log2; try order. discriminate.
+ apply le_lt_trans with (log2 b); trivial. now apply log2_le_mono.
+ rewrite <- H in LT. apply log2_lt_cancel in LT; order.
+ (* main *)
+ intros a b Ha Hb.
+ destruct (le_ge_cases a b) as [H|H].
+ rewrite max_r by now apply log2_le_mono. now apply AUX.
+ rewrite max_l by now apply log2_le_mono. rewrite lxor_comm. now apply AUX.
+Qed.
+
+(** Bitwise operations and arithmetical operations *)
+
+Local Notation xor3 a b c := (xorb (xorb a b) c).
+Local Notation lxor3 a b c := (lxor (lxor a b) c).
+Local Notation nextcarry a b c := ((a&&b) || (c && (a||b))).
+Local Notation lnextcarry a b c := (lor (land a b) (land c (lor a b))).
+
+Lemma add_bit0 : forall a b, (a+b).[0] = xorb a.[0] b.[0].
+Proof.
+ intros. now rewrite !bit0_odd, odd_add.
+Qed.
+
+Lemma add3_bit0 : forall a b c,
+ (a+b+c).[0] = xor3 a.[0] b.[0] c.[0].
+Proof.
+ intros. now rewrite !add_bit0.
+Qed.
+
+Lemma add3_bits_div2 : forall (a0 b0 c0 : bool),
+ (a0 + b0 + c0)/2 == nextcarry a0 b0 c0.
+Proof.
+ assert (H : 1+1 == 2) by now nzsimpl'.
+ intros [|] [|] [|]; simpl; rewrite ?add_0_l, ?add_0_r, ?H;
+ (apply div_same; order') || (apply div_small; split; order') || idtac.
+ symmetry. apply div_unique with 1. left; split; order'. now nzsimpl'.
+Qed.
+
+Lemma add_carry_div2 : forall a b (c0:bool),
+ (a + b + c0)/2 == a/2 + b/2 + nextcarry a.[0] b.[0] c0.
+Proof.
+ intros.
+ rewrite <- add3_bits_div2.
+ rewrite (add_comm ((a/2)+_)).
+ rewrite <- div_add by order'.
+ f_equiv.
+ rewrite <- !div2_div, mul_comm, mul_add_distr_l.
+ rewrite (div2_odd a), <- bit0_odd at 1.
+ rewrite (div2_odd b), <- bit0_odd at 1.
+ rewrite add_shuffle1.
+ rewrite <-(add_assoc _ _ c0). apply add_comm.
+Qed.
+
+(** The main result concerning addition: we express the bits of the sum
+ in term of bits of [a] and [b] and of some carry stream which is also
+ recursively determined by another equation.
+*)
+
+Lemma add_carry_bits_aux : forall n, 0<=n ->
+ forall a b (c0:bool), -(2^n) <= a < 2^n -> -(2^n) <= b < 2^n ->
+ exists c,
+ a+b+c0 == lxor3 a b c /\ c/2 == lnextcarry a b c /\ c.[0] = c0.
+Proof.
+ intros n Hn. apply le_ind with (4:=Hn).
+ solve_proper.
+ (* base *)
+ intros a b c0. rewrite !pow_0_r, !one_succ, !lt_succ_r, <- !one_succ.
+ intros (Ha1,Ha2) (Hb1,Hb2).
+ le_elim Ha1; rewrite <- ?le_succ_l, ?succ_m1 in Ha1;
+ le_elim Hb1; rewrite <- ?le_succ_l, ?succ_m1 in Hb1.
+ (* base, a = 0, b = 0 *)
+ exists c0.
+ rewrite (le_antisymm _ _ Ha2 Ha1), (le_antisymm _ _ Hb2 Hb1).
+ rewrite !add_0_l, !lxor_0_l, !lor_0_r, !land_0_r, !lor_0_r.
+ rewrite b2z_div2, b2z_bit0; now repeat split.
+ (* base, a = 0, b = -1 *)
+ exists (-c0). rewrite <- Hb1, (le_antisymm _ _ Ha2 Ha1). repeat split.
+ rewrite add_0_l, lxor_0_l, lxor_m1_l.
+ unfold lnot. now rewrite opp_involutive, add_comm, add_opp_r, sub_1_r.
+ rewrite land_0_l, !lor_0_l, land_m1_r.
+ symmetry. apply div_unique with c0. left; destruct c0; simpl; split; order'.
+ now rewrite two_succ, mul_succ_l, mul_1_l, add_opp_r, sub_add.
+ rewrite bit0_odd, odd_opp; destruct c0; simpl; apply odd_1 || apply odd_0.
+ (* base, a = -1, b = 0 *)
+ exists (-c0). rewrite <- Ha1, (le_antisymm _ _ Hb2 Hb1). repeat split.
+ rewrite add_0_r, lxor_0_r, lxor_m1_l.
+ unfold lnot. now rewrite opp_involutive, add_comm, add_opp_r, sub_1_r.
+ rewrite land_0_r, lor_0_r, lor_0_l, land_m1_r.
+ symmetry. apply div_unique with c0. left; destruct c0; simpl; split; order'.
+ now rewrite two_succ, mul_succ_l, mul_1_l, add_opp_r, sub_add.
+ rewrite bit0_odd, odd_opp; destruct c0; simpl; apply odd_1 || apply odd_0.
+ (* base, a = -1, b = -1 *)
+ exists (c0 + 2*(-1)). rewrite <- Ha1, <- Hb1. repeat split.
+ rewrite lxor_m1_l, lnot_m1, lxor_0_l.
+ now rewrite two_succ, mul_succ_l, mul_1_l, add_comm, add_assoc.
+ rewrite land_m1_l, lor_m1_l.
+ apply add_b2z_double_div2.
+ apply add_b2z_double_bit0.
+ (* step *)
+ clear n Hn. intros n Hn IH a b c0 Ha Hb.
+ set (c1:=nextcarry a.[0] b.[0] c0).
+ destruct (IH (a/2) (b/2) c1) as (c & IH1 & IH2 & Hc); clear IH.
+ split.
+ apply div_le_lower_bound. order'. now rewrite mul_opp_r, <- pow_succ_r.
+ apply div_lt_upper_bound. order'. now rewrite <- pow_succ_r.
+ split.
+ apply div_le_lower_bound. order'. now rewrite mul_opp_r, <- pow_succ_r.
+ apply div_lt_upper_bound. order'. now rewrite <- pow_succ_r.
+ exists (c0 + 2*c). repeat split.
+ (* step, add *)
+ bitwise.
+ le_elim Hm.
+ rewrite <- (succ_pred m), lt_succ_r in Hm.
+ rewrite <- (succ_pred m), <- !div2_bits, <- 2 lxor_spec by trivial.
+ f_equiv.
+ rewrite add_b2z_double_div2, <- IH1. apply add_carry_div2.
+ rewrite <- Hm.
+ now rewrite add_b2z_double_bit0, add3_bit0, b2z_bit0.
+ (* step, carry *)
+ rewrite add_b2z_double_div2.
+ bitwise.
+ le_elim Hm.
+ rewrite <- (succ_pred m), lt_succ_r in Hm.
+ rewrite <- (succ_pred m), <- !div2_bits, IH2 by trivial.
+ autorewrite with bitwise. now rewrite add_b2z_double_div2.
+ rewrite <- Hm.
+ now rewrite add_b2z_double_bit0.
+ (* step, carry0 *)
+ apply add_b2z_double_bit0.
+Qed.
+
+Lemma add_carry_bits : forall a b (c0:bool), exists c,
+ a+b+c0 == lxor3 a b c /\ c/2 == lnextcarry a b c /\ c.[0] = c0.
+Proof.
+ intros a b c0.
+ set (n := max (abs a) (abs b)).
+ apply (add_carry_bits_aux n).
+ (* positivity *)
+ unfold n.
+ destruct (le_ge_cases (abs a) (abs b));
+ [rewrite max_r|rewrite max_l]; order_pos'.
+ (* bound for a *)
+ assert (Ha : abs a < 2^n).
+ apply lt_le_trans with (2^(abs a)). apply pow_gt_lin_r; order_pos'.
+ apply pow_le_mono_r. order'. unfold n.
+ destruct (le_ge_cases (abs a) (abs b));
+ [rewrite max_r|rewrite max_l]; try order.
+ apply abs_lt in Ha. destruct Ha; split; order.
+ (* bound for b *)
+ assert (Hb : abs b < 2^n).
+ apply lt_le_trans with (2^(abs b)). apply pow_gt_lin_r; order_pos'.
+ apply pow_le_mono_r. order'. unfold n.
+ destruct (le_ge_cases (abs a) (abs b));
+ [rewrite max_r|rewrite max_l]; try order.
+ apply abs_lt in Hb. destruct Hb; split; order.
+Qed.
+
+(** Particular case : the second bit of an addition *)
+
+Lemma add_bit1 : forall a b,
+ (a+b).[1] = xor3 a.[1] b.[1] (a.[0] && b.[0]).
+Proof.
+ intros a b.
+ destruct (add_carry_bits a b false) as (c & EQ1 & EQ2 & Hc).
+ simpl in EQ1; rewrite add_0_r in EQ1. rewrite EQ1.
+ autorewrite with bitwise. f_equal.
+ rewrite one_succ, <- div2_bits, EQ2 by order.
+ autorewrite with bitwise.
+ rewrite Hc. simpl. apply orb_false_r.
+Qed.
+
+(** In an addition, there will be no carries iff there is
+ no common bits in the numbers to add *)
+
+Lemma nocarry_equiv : forall a b c,
+ c/2 == lnextcarry a b c -> c.[0] = false ->
+ (c == 0 <-> land a b == 0).
+Proof.
+ intros a b c H H'.
+ split. intros EQ; rewrite EQ in *.
+ rewrite div_0_l in H by order'.
+ symmetry in H. now apply lor_eq_0_l in H.
+ intros EQ. rewrite EQ, lor_0_l in H.
+ apply bits_inj'. intros n Hn. rewrite bits_0.
+ apply le_ind with (4:=Hn).
+ solve_proper.
+ trivial.
+ clear n Hn. intros n Hn IH.
+ rewrite <- div2_bits, H; trivial.
+ autorewrite with bitwise.
+ now rewrite IH.
+Qed.
+
+(** When there is no common bits, the addition is just a xor *)
+
+Lemma add_nocarry_lxor : forall a b, land a b == 0 ->
+ a+b == lxor a b.
+Proof.
+ intros a b H.
+ destruct (add_carry_bits a b false) as (c & EQ1 & EQ2 & Hc).
+ simpl in EQ1; rewrite add_0_r in EQ1. rewrite EQ1.
+ apply (nocarry_equiv a b c) in H; trivial.
+ rewrite H. now rewrite lxor_0_r.
+Qed.
+
+(** A null [ldiff] implies being smaller *)
+
+Lemma ldiff_le : forall a b, 0<=b -> ldiff a b == 0 -> 0 <= a <= b.
+Proof.
+ assert (AUX : forall n, 0<=n ->
+ forall a b, 0 <= a < 2^n -> 0<=b -> ldiff a b == 0 -> a <= b).
+ intros n Hn. apply le_ind with (4:=Hn); clear n Hn.
+ solve_proper.
+ intros a b Ha Hb _. rewrite pow_0_r, one_succ, lt_succ_r in Ha.
+ setoid_replace a with 0 by (destruct Ha; order'); trivial.
+ intros n Hn IH a b (Ha,Ha') Hb H.
+ assert (NEQ : 2 ~= 0) by order'.
+ rewrite (div_mod a 2 NEQ), (div_mod b 2 NEQ).
+ apply add_le_mono.
+ apply mul_le_mono_pos_l; try order'.
+ apply IH.
+ split. apply div_pos; order'.
+ apply div_lt_upper_bound; try order'. now rewrite <- pow_succ_r.
+ apply div_pos; order'.
+ rewrite <- (pow_1_r 2), <- 2 shiftr_div_pow2 by order'.
+ rewrite <- shiftr_ldiff, H, shiftr_div_pow2, pow_1_r, div_0_l; order'.
+ rewrite <- 2 bit0_mod.
+ apply bits_inj_iff in H. specialize (H 0).
+ rewrite ldiff_spec, bits_0 in H.
+ destruct a.[0], b.[0]; try discriminate; simpl; order'.
+ (* main *)
+ intros a b Hb Hd.
+ assert (Ha : 0<=a).
+ apply le_ngt; intros Ha'. apply (lt_irrefl 0). rewrite <- Hd at 1.
+ apply ldiff_neg. now split.
+ split; trivial. apply (AUX a); try split; trivial. apply pow_gt_lin_r; order'.
+Qed.
+
+(** Subtraction can be a ldiff when the opposite ldiff is null. *)
+
+Lemma sub_nocarry_ldiff : forall a b, ldiff b a == 0 ->
+ a-b == ldiff a b.
+Proof.
+ intros a b H.
+ apply add_cancel_r with b.
+ rewrite sub_add.
+ symmetry.
+ rewrite add_nocarry_lxor; trivial.
+ bitwise.
+ apply bits_inj_iff in H. specialize (H m).
+ rewrite ldiff_spec, bits_0 in H.
+ now destruct a.[m], b.[m].
+ apply land_ldiff.
+Qed.
+
+(** Adding numbers with no common bits cannot lead to a much bigger number *)
+
+Lemma add_nocarry_lt_pow2 : forall a b n, land a b == 0 ->
+ a < 2^n -> b < 2^n -> a+b < 2^n.
+Proof.
+ intros a b n H Ha Hb.
+ destruct (le_gt_cases a 0) as [Ha'|Ha'].
+ apply le_lt_trans with (0+b). now apply add_le_mono_r. now nzsimpl.
+ destruct (le_gt_cases b 0) as [Hb'|Hb'].
+ apply le_lt_trans with (a+0). now apply add_le_mono_l. now nzsimpl.
+ rewrite add_nocarry_lxor by order.
+ destruct (lt_ge_cases 0 (lxor a b)); [|apply le_lt_trans with 0; order_pos].
+ apply log2_lt_pow2; trivial.
+ apply log2_lt_pow2 in Ha; trivial.
+ apply log2_lt_pow2 in Hb; trivial.
+ apply le_lt_trans with (max (log2 a) (log2 b)).
+ apply log2_lxor; order.
+ destruct (le_ge_cases (log2 a) (log2 b));
+ [rewrite max_r|rewrite max_l]; order.
+Qed.
+
+Lemma add_nocarry_mod_lt_pow2 : forall a b n, 0<=n -> land a b == 0 ->
+ a mod 2^n + b mod 2^n < 2^n.
+Proof.
+ intros a b n Hn H.
+ apply add_nocarry_lt_pow2.
+ bitwise.
+ destruct (le_gt_cases n m).
+ rewrite mod_pow2_bits_high; now split.
+ now rewrite !mod_pow2_bits_low, <- land_spec, H, bits_0.
+ apply mod_pos_bound; order_pos.
+ apply mod_pos_bound; order_pos.
+Qed.
+
+End ZBitsProp.
diff --git a/theories/Numbers/Integer/Abstract/ZDivEucl.v b/theories/Numbers/Integer/Abstract/ZDivEucl.v
index 4555e733..fe951a75 100644
--- a/theories/Numbers/Integer/Abstract/ZDivEucl.v
+++ b/theories/Numbers/Integer/Abstract/ZDivEucl.v
@@ -1,11 +1,13 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
+Require Import ZAxioms ZMulOrder ZSgnAbs NZDiv.
+
(** * Euclidean Division for integers, Euclid convention
We use here the "usual" formulation of the Euclid Theorem
@@ -19,37 +21,29 @@
Vol. 14, No.2, pp. 127-144, April 1992.
See files [ZDivTrunc] and [ZDivFloor] for others conventions.
-*)
-
-Require Import ZAxioms ZProperties NZDiv.
-Module Type ZDivSpecific (Import Z : ZAxiomsExtSig')(Import DM : DivMod' Z).
- Axiom mod_always_pos : forall a b, 0 <= a mod b < abs b.
-End ZDivSpecific.
-
-Module Type ZDiv (Z:ZAxiomsExtSig)
- := DivMod Z <+ NZDivCommon Z <+ ZDivSpecific Z.
+ We simply extend NZDiv with a bound for modulo that holds
+ regardless of the sign of a and b. This new specification
+ subsume mod_bound_pos, which nonetheless stays there for
+ subtyping. Note also that ZAxiomSig now already contain
+ a div and a modulo (that follow the Floor convention).
+ We just ignore them here.
+*)
-Module Type ZDivSig := ZAxiomsExtSig <+ ZDiv.
-Module Type ZDivSig' := ZAxiomsExtSig' <+ ZDiv <+ DivModNotation.
+Module Type EuclidSpec (Import A : ZAxiomsSig')(Import B : DivMod' A).
+ Axiom mod_always_pos : forall a b, b ~= 0 -> 0 <= a mod b < abs b.
+End EuclidSpec.
-Module ZDivPropFunct (Import Z : ZDivSig')(Import ZP : ZPropSig Z).
+Module Type ZEuclid (Z:ZAxiomsSig) := NZDiv.NZDiv Z <+ EuclidSpec Z.
+Module Type ZEuclid' (Z:ZAxiomsSig) := NZDiv.NZDiv' Z <+ EuclidSpec Z.
-(** We benefit from what already exists for NZ *)
+Module ZEuclidProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZSgnAbsProp A B)
+ (Import D : ZEuclid' A).
- Module ZD <: NZDiv Z.
- Definition div := div.
- Definition modulo := modulo.
- Definition div_wd := div_wd.
- Definition mod_wd := mod_wd.
- Definition div_mod := div_mod.
- Lemma mod_bound : forall a b, 0<=a -> 0<b -> 0 <= a mod b < b.
- Proof.
- intros. rewrite <- (abs_eq b) at 3 by now apply lt_le_incl.
- apply mod_always_pos.
- Qed.
- End ZD.
- Module Import NZDivP := NZDivPropFunct Z ZP ZD.
+ Module Import Private_NZDiv := Nop <+ NZDivProp A D B.
(** Another formulation of the main equation *)
@@ -117,7 +111,7 @@ Lemma div_opp_r : forall a b, b~=0 -> a/(-b) == -(a/b).
Proof.
intros. symmetry.
apply div_unique with (a mod b).
-rewrite abs_opp; apply mod_always_pos.
+rewrite abs_opp; now apply mod_always_pos.
rewrite mul_opp_opp; now apply div_mod.
Qed.
@@ -125,7 +119,7 @@ Lemma mod_opp_r : forall a b, b~=0 -> a mod (-b) == a mod b.
Proof.
intros. symmetry.
apply mod_unique with (-(a/b)).
-rewrite abs_opp; apply mod_always_pos.
+rewrite abs_opp; now apply mod_always_pos.
rewrite mul_opp_opp; now apply div_mod.
Qed.
@@ -274,6 +268,11 @@ Proof.
intros. rewrite mod_eq, div_mul by trivial. rewrite mul_comm; apply sub_diag.
Qed.
+Theorem div_unique_exact a b q: b~=0 -> a == b*q -> q == a/b.
+Proof.
+ intros Hb H. rewrite H, mul_comm. symmetry. now apply div_mul.
+Qed.
+
(** * Order results about mod and div *)
(** A modulo cannot grow beyond its starting point. *)
@@ -296,7 +295,7 @@ intros a b Hb.
split.
intros EQ.
rewrite (div_mod a b Hb), EQ; nzsimpl.
-apply mod_always_pos.
+now apply mod_always_pos.
intros. pos_or_neg b.
apply div_small.
now rewrite <- (abs_eq b).
@@ -365,7 +364,7 @@ intros.
nzsimpl.
rewrite (div_mod a b) at 1; try order.
rewrite <- add_lt_mono_l.
-destruct (mod_always_pos a b).
+destruct (mod_always_pos a b). order.
rewrite abs_eq in *; order.
Qed.
@@ -375,7 +374,7 @@ intros a b Hb.
rewrite mul_pred_r, <- add_opp_r.
rewrite (div_mod a b) at 1; try order.
rewrite <- add_lt_mono_l.
-destruct (mod_always_pos a b).
+destruct (mod_always_pos a b). order.
rewrite <- opp_pos_neg in Hb. rewrite abs_neq' in *; order.
Qed.
@@ -469,7 +468,7 @@ apply div_unique with ((a mod b)*c).
(* ineqs *)
rewrite abs_mul, (abs_eq c) by order.
rewrite <-(mul_0_l c), <-mul_lt_mono_pos_r, <-mul_le_mono_pos_r by trivial.
-apply mod_always_pos.
+now apply mod_always_pos.
(* equation *)
rewrite (div_mod a b) at 1 by order.
rewrite mul_add_distr_r.
@@ -556,17 +555,18 @@ Proof.
Qed.
(** With the current convention, the following result isn't always
- true for negative divisors. For instance
- [ 3/(-2)/(-2) = 1 <> 0 = 3 / (-2*-2) ]. *)
+ true with a negative intermediate divisor. For instance
+ [ 3/(-2)/(-2) = 1 <> 0 = 3 / (-2*-2) ] and
+ [ 3/(-2)/2 = -1 <> 0 = 3 / (-2*2) ]. *)
-Lemma div_div : forall a b c, 0<b -> 0<c ->
+Lemma div_div : forall a b c, 0<b -> c~=0 ->
(a/b)/c == a/(b*c).
Proof.
intros a b c Hb Hc.
apply div_unique with (b*((a/b) mod c) + a mod b).
(* begin 0<= ... <abs(b*c) *)
rewrite abs_mul.
- destruct (mod_always_pos (a/b) c), (mod_always_pos a b).
+ destruct (mod_always_pos (a/b) c), (mod_always_pos a b); try order.
split.
apply add_nonneg_nonneg; trivial.
apply mul_nonneg_nonneg; order.
@@ -581,6 +581,22 @@ Proof.
apply div_mod; order.
Qed.
+(** Similarly, the following result doesn't always hold when [b<0].
+ For instance [3 mod (-2*-2)) = 3] while
+ [3 mod (-2) + (-2)*((3/-2) mod -2) = -1]. *)
+
+Lemma mod_mul_r : forall a b c, 0<b -> c~=0 ->
+ a mod (b*c) == a mod b + b*((a/b) mod c).
+Proof.
+ intros a b c Hb Hc.
+ apply add_cancel_l with (b*c*(a/(b*c))).
+ rewrite <- div_mod by (apply neq_mul_0; split; order).
+ rewrite <- div_div by trivial.
+ rewrite add_assoc, add_shuffle0, <- mul_assoc, <- mul_add_distr_l.
+ rewrite <- div_mod by order.
+ apply div_mod; order.
+Qed.
+
(** A last inequality: *)
Theorem div_mul_le:
@@ -590,16 +606,13 @@ Proof. exact div_mul_le. Qed.
(** mod is related to divisibility *)
Lemma mod_divides : forall a b, b~=0 ->
- (a mod b == 0 <-> exists c, a == b*c).
+ (a mod b == 0 <-> (b|a)).
Proof.
intros a b Hb. split.
-intros Hab. exists (a/b). rewrite (div_mod a b Hb) at 1.
- rewrite Hab; now nzsimpl.
-intros (c,Hc).
-rewrite Hc, mul_comm.
-now apply mod_mul.
+intros Hab. exists (a/b). rewrite mul_comm.
+ rewrite (div_mod a b Hb) at 1. rewrite Hab; now nzsimpl.
+intros (c,Hc). rewrite Hc. now apply mod_mul.
Qed.
-
-End ZDivPropFunct.
+End ZEuclidProp.
diff --git a/theories/Numbers/Integer/Abstract/ZDivFloor.v b/theories/Numbers/Integer/Abstract/ZDivFloor.v
index efefab81..14003d89 100644
--- a/theories/Numbers/Integer/Abstract/ZDivFloor.v
+++ b/theories/Numbers/Integer/Abstract/ZDivFloor.v
@@ -1,11 +1,13 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
+Require Import ZAxioms ZMulOrder ZSgnAbs NZDiv.
+
(** * Euclidean Division for integers (Floor convention)
We use here the convention known as Floor, or Round-Toward-Bottom,
@@ -24,33 +26,13 @@
See files [ZDivTrunc] and [ZDivEucl] for others conventions.
*)
-Require Import ZAxioms ZProperties NZDiv.
-
-Module Type ZDivSpecific (Import Z:ZAxiomsSig')(Import DM : DivMod' Z).
- Axiom mod_pos_bound : forall a b, 0 < b -> 0 <= a mod b < b.
- Axiom mod_neg_bound : forall a b, b < 0 -> b < a mod b <= 0.
-End ZDivSpecific.
-
-Module Type ZDiv (Z:ZAxiomsSig)
- := DivMod Z <+ NZDivCommon Z <+ ZDivSpecific Z.
-
-Module Type ZDivSig := ZAxiomsExtSig <+ ZDiv.
-Module Type ZDivSig' := ZAxiomsExtSig' <+ ZDiv <+ DivModNotation.
-
-Module ZDivPropFunct (Import Z : ZDivSig')(Import ZP : ZPropSig Z).
+Module Type ZDivProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZSgnAbsProp A B).
(** We benefit from what already exists for NZ *)
-
- Module ZD <: NZDiv Z.
- Definition div := div.
- Definition modulo := modulo.
- Definition div_wd := div_wd.
- Definition mod_wd := mod_wd.
- Definition div_mod := div_mod.
- Lemma mod_bound : forall a b, 0<=a -> 0<b -> 0 <= a mod b < b.
- Proof. intros. now apply mod_pos_bound. Qed.
- End ZD.
- Module Import NZDivP := NZDivPropFunct Z ZP ZD.
+Module Import Private_NZDiv := Nop <+ NZDivProp A A B.
(** Another formulation of the main equation *)
@@ -62,6 +44,18 @@ rewrite <- add_move_l.
symmetry. now apply div_mod.
Qed.
+(** We have a general bound for absolute values *)
+
+Lemma mod_bound_abs :
+ forall a b, b~=0 -> abs (a mod b) < abs b.
+Proof.
+intros.
+destruct (abs_spec b) as [(LE,EQ)|(LE,EQ)]; rewrite EQ.
+destruct (mod_pos_bound a b). order. now rewrite abs_eq.
+destruct (mod_neg_bound a b). order. rewrite abs_neq; trivial.
+now rewrite <- opp_lt_mono.
+Qed.
+
(** Uniqueness theorems *)
Theorem div_mod_unique : forall b q1 q2 r1 r2 : t,
@@ -94,7 +88,7 @@ Theorem div_unique_pos:
Proof. intros; apply div_unique with r; auto. Qed.
Theorem div_unique_neg:
- forall a b q r, 0<=r<b -> a == b*q + r -> q == a/b.
+ forall a b q r, b<r<=0 -> a == b*q + r -> q == a/b.
Proof. intros; apply div_unique with r; auto. Qed.
Theorem mod_unique:
@@ -230,11 +224,26 @@ rewrite mod_opp_opp, mod_opp_l_nz by trivial.
now rewrite opp_sub_distr, add_comm, add_opp_r.
Qed.
-(** The sign of [a mod b] is the one of [b] *)
+(** The sign of [a mod b] is the one of [b] (when it isn't null) *)
+
+Lemma mod_sign_nz : forall a b, b~=0 -> a mod b ~= 0 ->
+ sgn (a mod b) == sgn b.
+Proof.
+intros a b Hb H. destruct (lt_ge_cases 0 b) as [Hb'|Hb'].
+destruct (mod_pos_bound a b Hb'). rewrite 2 sgn_pos; order.
+destruct (mod_neg_bound a b). order. rewrite 2 sgn_neg; order.
+Qed.
-(* TODO: a proper sgn function and theory *)
+Lemma mod_sign : forall a b, b~=0 -> sgn (a mod b) ~= -sgn b.
+Proof.
+intros a b Hb H.
+destruct (eq_decidable (a mod b) 0) as [EQ|NEQ].
+apply Hb, sgn_null_iff, opp_inj. now rewrite <- H, opp_0, EQ, sgn_0.
+apply Hb, sgn_null_iff. apply eq_mul_0_l with 2; try order'. nzsimpl'.
+apply add_move_0_l. rewrite <- H. symmetry. now apply mod_sign_nz.
+Qed.
-Lemma mod_sign : forall a b, b~=0 -> (0 <= (a mod b) * b).
+Lemma mod_sign_mul : forall a b, b~=0 -> 0 <= (a mod b) * b.
Proof.
intros. destruct (lt_ge_cases 0 b).
apply mul_nonneg_nonneg; destruct (mod_pos_bound a b); order.
@@ -307,6 +316,11 @@ Proof.
intros. rewrite mod_eq, div_mul by trivial. rewrite mul_comm; apply sub_diag.
Qed.
+Theorem div_unique_exact a b q: b~=0 -> a == b*q -> q == a/b.
+Proof.
+ intros Hb H. rewrite H, mul_comm. symmetry. now apply div_mul.
+Qed.
+
(** * Order results about mod and div *)
(** A modulo cannot grow beyond its starting point. *)
@@ -585,15 +599,25 @@ Proof.
Qed.
(** With the current convention, the following result isn't always
- true for negative divisors. For instance
- [ 3/(-2)/(-2) = 1 <> 0 = 3 / (-2*-2) ]. *)
+ true with a negative last divisor. For instance
+ [ 3/(-2)/(-2) = 1 <> 0 = 3 / (-2*-2) ], or
+ [ 5/2/(-2) = -1 <> -2 = 5 / (2*-2) ]. *)
-Lemma div_div : forall a b c, 0<b -> 0<c ->
+Lemma div_div : forall a b c, b~=0 -> 0<c ->
(a/b)/c == a/(b*c).
Proof.
intros a b c Hb Hc.
apply div_unique with (b*((a/b) mod c) + a mod b).
(* begin 0<= ... <b*c \/ ... *)
+ apply neg_pos_cases in Hb. destruct Hb as [Hb|Hb].
+ right.
+ destruct (mod_pos_bound (a/b) c), (mod_neg_bound a b); trivial.
+ split.
+ apply le_lt_trans with (b*((a/b) mod c) + b).
+ now rewrite <- mul_succ_r, <- mul_le_mono_neg_l, le_succ_l.
+ now rewrite <- add_lt_mono_l.
+ apply add_nonpos_nonpos; trivial.
+ apply mul_nonpos_nonneg; order.
left.
destruct (mod_pos_bound (a/b) c), (mod_pos_bound a b); trivial.
split.
@@ -609,24 +633,27 @@ Proof.
apply div_mod; order.
Qed.
+(** Similarly, the following result doesn't always hold when [c<0].
+ For instance [3 mod (-2*-2)) = 3] while
+ [3 mod (-2) + (-2)*((3/-2) mod -2) = -1].
+*)
+
+Lemma rem_mul_r : forall a b c, b~=0 -> 0<c ->
+ a mod (b*c) == a mod b + b*((a/b) mod c).
+Proof.
+ intros a b c Hb Hc.
+ apply add_cancel_l with (b*c*(a/(b*c))).
+ rewrite <- div_mod by (apply neq_mul_0; split; order).
+ rewrite <- div_div by trivial.
+ rewrite add_assoc, add_shuffle0, <- mul_assoc, <- mul_add_distr_l.
+ rewrite <- div_mod by order.
+ apply div_mod; order.
+Qed.
+
(** A last inequality: *)
Theorem div_mul_le:
forall a b c, 0<=a -> 0<b -> 0<=c -> c*(a/b) <= (c*a)/b.
Proof. exact div_mul_le. Qed.
-(** mod is related to divisibility *)
-
-Lemma mod_divides : forall a b, b~=0 ->
- (a mod b == 0 <-> exists c, a == b*c).
-Proof.
-intros a b Hb. split.
-intros Hab. exists (a/b). rewrite (div_mod a b Hb) at 1.
- rewrite Hab. now nzsimpl.
-intros (c,Hc).
-rewrite Hc, mul_comm.
-now apply mod_mul.
-Qed.
-
-End ZDivPropFunct.
-
+End ZDivProp.
diff --git a/theories/Numbers/Integer/Abstract/ZDivTrunc.v b/theories/Numbers/Integer/Abstract/ZDivTrunc.v
index 069d8a8d..bd8b6ce2 100644
--- a/theories/Numbers/Integer/Abstract/ZDivTrunc.v
+++ b/theories/Numbers/Integer/Abstract/ZDivTrunc.v
@@ -1,11 +1,13 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
+Require Import ZAxioms ZMulOrder ZSgnAbs NZDiv.
+
(** * Euclidean Division for integers (Trunc convention)
We use here the convention known as Trunc, or Round-Toward-Zero,
@@ -24,25 +26,24 @@
See files [ZDivFloor] and [ZDivEucl] for others conventions.
*)
-Require Import ZAxioms ZProperties NZDiv.
-
-Module Type ZDivSpecific (Import Z:ZAxiomsSig')(Import DM : DivMod' Z).
- Axiom mod_bound : forall a b, 0<=a -> 0<b -> 0 <= a mod b < b.
- Axiom mod_opp_l : forall a b, b ~= 0 -> (-a) mod b == - (a mod b).
- Axiom mod_opp_r : forall a b, b ~= 0 -> a mod (-b) == a mod b.
-End ZDivSpecific.
-
-Module Type ZDiv (Z:ZAxiomsSig)
- := DivMod Z <+ NZDivCommon Z <+ ZDivSpecific Z.
-
-Module Type ZDivSig := ZAxiomsExtSig <+ ZDiv.
-Module Type ZDivSig' := ZAxiomsExtSig' <+ ZDiv <+ DivModNotation.
-
-Module ZDivPropFunct (Import Z : ZDivSig')(Import ZP : ZPropSig Z).
+Module Type ZQuotProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZSgnAbsProp A B).
(** We benefit from what already exists for NZ *)
- Module Import NZDivP := NZDivPropFunct Z ZP Z.
+ Module Import Private_Div.
+ Module Quot2Div <: NZDiv A.
+ Definition div := quot.
+ Definition modulo := A.rem.
+ Definition div_wd := quot_wd.
+ Definition mod_wd := rem_wd.
+ Definition div_mod := quot_rem.
+ Definition mod_bound_pos := rem_bound_pos.
+ End Quot2Div.
+ Module NZQuot := Nop <+ NZDivProp A Quot2Div B.
+ End Private_Div.
Ltac pos_or_neg a :=
let LT := fresh "LT" in
@@ -51,175 +52,274 @@ Ltac pos_or_neg a :=
(** Another formulation of the main equation *)
-Lemma mod_eq :
- forall a b, b~=0 -> a mod b == a - b*(a/b).
+Lemma rem_eq :
+ forall a b, b~=0 -> a rem b == a - b*(a÷b).
Proof.
intros.
rewrite <- add_move_l.
-symmetry. now apply div_mod.
+symmetry. now apply quot_rem.
Qed.
(** A few sign rules (simple ones) *)
-Lemma mod_opp_opp : forall a b, b ~= 0 -> (-a) mod (-b) == - (a mod b).
-Proof. intros. now rewrite mod_opp_r, mod_opp_l. Qed.
+Lemma rem_opp_opp : forall a b, b ~= 0 -> (-a) rem (-b) == - (a rem b).
+Proof. intros. now rewrite rem_opp_r, rem_opp_l. Qed.
-Lemma div_opp_l : forall a b, b ~= 0 -> (-a)/b == -(a/b).
+Lemma quot_opp_l : forall a b, b ~= 0 -> (-a)÷b == -(a÷b).
Proof.
intros.
rewrite <- (mul_cancel_l _ _ b) by trivial.
-rewrite <- (add_cancel_r _ _ ((-a) mod b)).
-now rewrite <- div_mod, mod_opp_l, mul_opp_r, <- opp_add_distr, <- div_mod.
+rewrite <- (add_cancel_r _ _ ((-a) rem b)).
+now rewrite <- quot_rem, rem_opp_l, mul_opp_r, <- opp_add_distr, <- quot_rem.
Qed.
-Lemma div_opp_r : forall a b, b ~= 0 -> a/(-b) == -(a/b).
+Lemma quot_opp_r : forall a b, b ~= 0 -> a÷(-b) == -(a÷b).
Proof.
intros.
assert (-b ~= 0) by (now rewrite eq_opp_l, opp_0).
rewrite <- (mul_cancel_l _ _ (-b)) by trivial.
-rewrite <- (add_cancel_r _ _ (a mod (-b))).
-now rewrite <- div_mod, mod_opp_r, mul_opp_opp, <- div_mod.
-Qed.
-
-Lemma div_opp_opp : forall a b, b ~= 0 -> (-a)/(-b) == a/b.
-Proof. intros. now rewrite div_opp_r, div_opp_l, opp_involutive. Qed.
-
-(** The sign of [a mod b] is the one of [a] *)
-
-(* TODO: a proper sgn function and theory *)
-
-Lemma mod_sign : forall a b, b~=0 -> 0 <= (a mod b) * a.
-Proof.
-assert (Aux : forall a b, 0<b -> 0 <= (a mod b) * a).
- intros. pos_or_neg a.
- apply mul_nonneg_nonneg; trivial. now destruct (mod_bound a b).
- rewrite <- mul_opp_opp, <- mod_opp_l by order.
- apply mul_nonneg_nonneg; try order. destruct (mod_bound (-a) b); order.
-intros. pos_or_neg b. apply Aux; order.
-rewrite <- mod_opp_r by order. apply Aux; order.
+rewrite <- (add_cancel_r _ _ (a rem (-b))).
+now rewrite <- quot_rem, rem_opp_r, mul_opp_opp, <- quot_rem.
Qed.
+Lemma quot_opp_opp : forall a b, b ~= 0 -> (-a)÷(-b) == a÷b.
+Proof. intros. now rewrite quot_opp_r, quot_opp_l, opp_involutive. Qed.
(** Uniqueness theorems *)
-Theorem div_mod_unique : forall b q1 q2 r1 r2 : t,
+Theorem quot_rem_unique : forall b q1 q2 r1 r2 : t,
(0<=r1<b \/ b<r1<=0) -> (0<=r2<b \/ b<r2<=0) ->
b*q1+r1 == b*q2+r2 -> q1 == q2 /\ r1 == r2.
Proof.
intros b q1 q2 r1 r2 Hr1 Hr2 EQ.
destruct Hr1; destruct Hr2; try (intuition; order).
-apply div_mod_unique with b; trivial.
+apply NZQuot.div_mod_unique with b; trivial.
rewrite <- (opp_inj_wd r1 r2).
-apply div_mod_unique with (-b); trivial.
+apply NZQuot.div_mod_unique with (-b); trivial.
rewrite <- opp_lt_mono, opp_nonneg_nonpos; tauto.
rewrite <- opp_lt_mono, opp_nonneg_nonpos; tauto.
now rewrite 2 mul_opp_l, <- 2 opp_add_distr, opp_inj_wd.
Qed.
-Theorem div_unique:
- forall a b q r, 0<=a -> 0<=r<b -> a == b*q + r -> q == a/b.
-Proof. intros; now apply div_unique with r. Qed.
+Theorem quot_unique:
+ forall a b q r, 0<=a -> 0<=r<b -> a == b*q + r -> q == a÷b.
+Proof. intros; now apply NZQuot.div_unique with r. Qed.
-Theorem mod_unique:
- forall a b q r, 0<=a -> 0<=r<b -> a == b*q + r -> r == a mod b.
-Proof. intros; now apply mod_unique with q. Qed.
+Theorem rem_unique:
+ forall a b q r, 0<=a -> 0<=r<b -> a == b*q + r -> r == a rem b.
+Proof. intros; now apply NZQuot.mod_unique with q. Qed.
(** A division by itself returns 1 *)
-Lemma div_same : forall a, a~=0 -> a/a == 1.
+Lemma quot_same : forall a, a~=0 -> a÷a == 1.
Proof.
-intros. pos_or_neg a. apply div_same; order.
-rewrite <- div_opp_opp by trivial. now apply div_same.
+intros. pos_or_neg a. apply NZQuot.div_same; order.
+rewrite <- quot_opp_opp by trivial. now apply NZQuot.div_same.
Qed.
-Lemma mod_same : forall a, a~=0 -> a mod a == 0.
+Lemma rem_same : forall a, a~=0 -> a rem a == 0.
Proof.
-intros. rewrite mod_eq, div_same by trivial. nzsimpl. apply sub_diag.
+intros. rewrite rem_eq, quot_same by trivial. nzsimpl. apply sub_diag.
Qed.
(** A division of a small number by a bigger one yields zero. *)
-Theorem div_small: forall a b, 0<=a<b -> a/b == 0.
-Proof. exact div_small. Qed.
+Theorem quot_small: forall a b, 0<=a<b -> a÷b == 0.
+Proof. exact NZQuot.div_small. Qed.
-(** Same situation, in term of modulo: *)
+(** Same situation, in term of remulo: *)
-Theorem mod_small: forall a b, 0<=a<b -> a mod b == a.
-Proof. exact mod_small. Qed.
+Theorem rem_small: forall a b, 0<=a<b -> a rem b == a.
+Proof. exact NZQuot.mod_small. Qed.
(** * Basic values of divisions and modulo. *)
-Lemma div_0_l: forall a, a~=0 -> 0/a == 0.
+Lemma quot_0_l: forall a, a~=0 -> 0÷a == 0.
Proof.
-intros. pos_or_neg a. apply div_0_l; order.
-rewrite <- div_opp_opp, opp_0 by trivial. now apply div_0_l.
+intros. pos_or_neg a. apply NZQuot.div_0_l; order.
+rewrite <- quot_opp_opp, opp_0 by trivial. now apply NZQuot.div_0_l.
Qed.
-Lemma mod_0_l: forall a, a~=0 -> 0 mod a == 0.
+Lemma rem_0_l: forall a, a~=0 -> 0 rem a == 0.
Proof.
-intros; rewrite mod_eq, div_0_l; now nzsimpl.
+intros; rewrite rem_eq, quot_0_l; now nzsimpl.
Qed.
-Lemma div_1_r: forall a, a/1 == a.
+Lemma quot_1_r: forall a, a÷1 == a.
Proof.
-intros. pos_or_neg a. now apply div_1_r.
-apply opp_inj. rewrite <- div_opp_l. apply div_1_r; order.
+intros. pos_or_neg a. now apply NZQuot.div_1_r.
+apply opp_inj. rewrite <- quot_opp_l. apply NZQuot.div_1_r; order.
intro EQ; symmetry in EQ; revert EQ; apply lt_neq, lt_0_1.
Qed.
-Lemma mod_1_r: forall a, a mod 1 == 0.
+Lemma rem_1_r: forall a, a rem 1 == 0.
Proof.
-intros. rewrite mod_eq, div_1_r; nzsimpl; auto using sub_diag.
+intros. rewrite rem_eq, quot_1_r; nzsimpl; auto using sub_diag.
intro EQ; symmetry in EQ; revert EQ; apply lt_neq; apply lt_0_1.
Qed.
-Lemma div_1_l: forall a, 1<a -> 1/a == 0.
-Proof. exact div_1_l. Qed.
+Lemma quot_1_l: forall a, 1<a -> 1÷a == 0.
+Proof. exact NZQuot.div_1_l. Qed.
+
+Lemma rem_1_l: forall a, 1<a -> 1 rem a == 1.
+Proof. exact NZQuot.mod_1_l. Qed.
-Lemma mod_1_l: forall a, 1<a -> 1 mod a == 1.
-Proof. exact mod_1_l. Qed.
+Lemma quot_mul : forall a b, b~=0 -> (a*b)÷b == a.
+Proof.
+intros. pos_or_neg a; pos_or_neg b. apply NZQuot.div_mul; order.
+rewrite <- quot_opp_opp, <- mul_opp_r by order. apply NZQuot.div_mul; order.
+rewrite <- opp_inj_wd, <- quot_opp_l, <- mul_opp_l by order.
+apply NZQuot.div_mul; order.
+rewrite <- opp_inj_wd, <- quot_opp_r, <- mul_opp_opp by order.
+apply NZQuot.div_mul; order.
+Qed.
-Lemma div_mul : forall a b, b~=0 -> (a*b)/b == a.
+Lemma rem_mul : forall a b, b~=0 -> (a*b) rem b == 0.
Proof.
-intros. pos_or_neg a; pos_or_neg b. apply div_mul; order.
-rewrite <- div_opp_opp, <- mul_opp_r by order. apply div_mul; order.
-rewrite <- opp_inj_wd, <- div_opp_l, <- mul_opp_l by order. apply div_mul; order.
-rewrite <- opp_inj_wd, <- div_opp_r, <- mul_opp_opp by order. apply div_mul; order.
+intros. rewrite rem_eq, quot_mul by trivial. rewrite mul_comm; apply sub_diag.
Qed.
-Lemma mod_mul : forall a b, b~=0 -> (a*b) mod b == 0.
+Theorem quot_unique_exact a b q: b~=0 -> a == b*q -> q == a÷b.
Proof.
-intros. rewrite mod_eq, div_mul by trivial. rewrite mul_comm; apply sub_diag.
+ intros Hb H. rewrite H, mul_comm. symmetry. now apply quot_mul.
Qed.
-(** * Order results about mod and div *)
+(** The sign of [a rem b] is the one of [a] (when it's not null) *)
+
+Lemma rem_nonneg : forall a b, b~=0 -> 0 <= a -> 0 <= a rem b.
+Proof.
+ intros. pos_or_neg b. destruct (rem_bound_pos a b); order.
+ rewrite <- rem_opp_r; trivial.
+ destruct (rem_bound_pos a (-b)); trivial.
+Qed.
+
+Lemma rem_nonpos : forall a b, b~=0 -> a <= 0 -> a rem b <= 0.
+Proof.
+ intros a b Hb Ha.
+ apply opp_nonneg_nonpos. apply opp_nonneg_nonpos in Ha.
+ rewrite <- rem_opp_l by trivial. now apply rem_nonneg.
+Qed.
+
+Lemma rem_sign_mul : forall a b, b~=0 -> 0 <= (a rem b) * a.
+Proof.
+intros a b Hb. destruct (le_ge_cases 0 a).
+ apply mul_nonneg_nonneg; trivial. now apply rem_nonneg.
+ apply mul_nonpos_nonpos; trivial. now apply rem_nonpos.
+Qed.
+
+Lemma rem_sign_nz : forall a b, b~=0 -> a rem b ~= 0 ->
+ sgn (a rem b) == sgn a.
+Proof.
+intros a b Hb H. destruct (lt_trichotomy 0 a) as [LT|[EQ|LT]].
+rewrite 2 sgn_pos; try easy.
+ generalize (rem_nonneg a b Hb (lt_le_incl _ _ LT)). order.
+now rewrite <- EQ, rem_0_l, sgn_0.
+rewrite 2 sgn_neg; try easy.
+ generalize (rem_nonpos a b Hb (lt_le_incl _ _ LT)). order.
+Qed.
+
+Lemma rem_sign : forall a b, a~=0 -> b~=0 -> sgn (a rem b) ~= -sgn a.
+Proof.
+intros a b Ha Hb H.
+destruct (eq_decidable (a rem b) 0) as [EQ|NEQ].
+apply Ha, sgn_null_iff, opp_inj. now rewrite <- H, opp_0, EQ, sgn_0.
+apply Ha, sgn_null_iff. apply eq_mul_0_l with 2; try order'. nzsimpl'.
+apply add_move_0_l. rewrite <- H. symmetry. now apply rem_sign_nz.
+Qed.
+
+(** Operations and absolute value *)
+
+Lemma rem_abs_l : forall a b, b ~= 0 -> (abs a) rem b == abs (a rem b).
+Proof.
+intros a b Hb. destruct (le_ge_cases 0 a) as [LE|LE].
+rewrite 2 abs_eq; try easy. now apply rem_nonneg.
+rewrite 2 abs_neq, rem_opp_l; try easy. now apply rem_nonpos.
+Qed.
+
+Lemma rem_abs_r : forall a b, b ~= 0 -> a rem (abs b) == a rem b.
+Proof.
+intros a b Hb. destruct (le_ge_cases 0 b).
+now rewrite abs_eq. now rewrite abs_neq, ?rem_opp_r.
+Qed.
+
+Lemma rem_abs : forall a b, b ~= 0 -> (abs a) rem (abs b) == abs (a rem b).
+Proof.
+intros. now rewrite rem_abs_r, rem_abs_l.
+Qed.
+
+Lemma quot_abs_l : forall a b, b ~= 0 -> (abs a)÷b == (sgn a)*(a÷b).
+Proof.
+intros a b Hb. destruct (lt_trichotomy 0 a) as [LT|[EQ|LT]].
+rewrite abs_eq, sgn_pos by order. now nzsimpl.
+rewrite <- EQ, abs_0, quot_0_l; trivial. now nzsimpl.
+rewrite abs_neq, quot_opp_l, sgn_neg by order.
+ rewrite mul_opp_l. now nzsimpl.
+Qed.
+
+Lemma quot_abs_r : forall a b, b ~= 0 -> a÷(abs b) == (sgn b)*(a÷b).
+Proof.
+intros a b Hb. destruct (lt_trichotomy 0 b) as [LT|[EQ|LT]].
+rewrite abs_eq, sgn_pos by order. now nzsimpl.
+order.
+rewrite abs_neq, quot_opp_r, sgn_neg by order.
+ rewrite mul_opp_l. now nzsimpl.
+Qed.
+
+Lemma quot_abs : forall a b, b ~= 0 -> (abs a)÷(abs b) == abs (a÷b).
+Proof.
+intros a b Hb.
+pos_or_neg a; [rewrite (abs_eq a)|rewrite (abs_neq a)];
+ try apply opp_nonneg_nonpos; try order.
+pos_or_neg b; [rewrite (abs_eq b)|rewrite (abs_neq b)];
+ try apply opp_nonneg_nonpos; try order.
+rewrite abs_eq; try easy. apply NZQuot.div_pos; order.
+rewrite <- abs_opp, <- quot_opp_r, abs_eq; try easy.
+ apply NZQuot.div_pos; order.
+pos_or_neg b; [rewrite (abs_eq b)|rewrite (abs_neq b)];
+ try apply opp_nonneg_nonpos; try order.
+rewrite <- (abs_opp (_÷_)), <- quot_opp_l, abs_eq; try easy.
+ apply NZQuot.div_pos; order.
+rewrite <- (quot_opp_opp a b), abs_eq; try easy.
+ apply NZQuot.div_pos; order.
+Qed.
+
+(** We have a general bound for absolute values *)
+
+Lemma rem_bound_abs :
+ forall a b, b~=0 -> abs (a rem b) < abs b.
+Proof.
+intros. rewrite <- rem_abs; trivial.
+apply rem_bound_pos. apply abs_nonneg. now apply abs_pos.
+Qed.
+
+(** * Order results about rem and quot *)
(** A modulo cannot grow beyond its starting point. *)
-Theorem mod_le: forall a b, 0<=a -> 0<b -> a mod b <= a.
-Proof. exact mod_le. Qed.
+Theorem rem_le: forall a b, 0<=a -> 0<b -> a rem b <= a.
+Proof. exact NZQuot.mod_le. Qed.
-Theorem div_pos : forall a b, 0<=a -> 0<b -> 0<= a/b.
-Proof. exact div_pos. Qed.
+Theorem quot_pos : forall a b, 0<=a -> 0<b -> 0<= a÷b.
+Proof. exact NZQuot.div_pos. Qed.
-Lemma div_str_pos : forall a b, 0<b<=a -> 0 < a/b.
-Proof. exact div_str_pos. Qed.
+Lemma quot_str_pos : forall a b, 0<b<=a -> 0 < a÷b.
+Proof. exact NZQuot.div_str_pos. Qed.
-Lemma div_small_iff : forall a b, b~=0 -> (a/b==0 <-> abs a < abs b).
+Lemma quot_small_iff : forall a b, b~=0 -> (a÷b==0 <-> abs a < abs b).
Proof.
intros. pos_or_neg a; pos_or_neg b.
-rewrite div_small_iff; try order. rewrite 2 abs_eq; intuition; order.
-rewrite <- opp_inj_wd, opp_0, <- div_opp_r, div_small_iff by order.
+rewrite NZQuot.div_small_iff; try order. rewrite 2 abs_eq; intuition; order.
+rewrite <- opp_inj_wd, opp_0, <- quot_opp_r, NZQuot.div_small_iff by order.
rewrite (abs_eq a), (abs_neq' b); intuition; order.
-rewrite <- opp_inj_wd, opp_0, <- div_opp_l, div_small_iff by order.
+rewrite <- opp_inj_wd, opp_0, <- quot_opp_l, NZQuot.div_small_iff by order.
rewrite (abs_neq' a), (abs_eq b); intuition; order.
-rewrite <- div_opp_opp, div_small_iff by order.
+rewrite <- quot_opp_opp, NZQuot.div_small_iff by order.
rewrite (abs_neq' a), (abs_neq' b); intuition; order.
Qed.
-Lemma mod_small_iff : forall a b, b~=0 -> (a mod b == a <-> abs a < abs b).
+Lemma rem_small_iff : forall a b, b~=0 -> (a rem b == a <-> abs a < abs b).
Proof.
-intros. rewrite mod_eq, <- div_small_iff by order.
+intros. rewrite rem_eq, <- quot_small_iff by order.
rewrite sub_move_r, <- (add_0_r a) at 1. rewrite add_cancel_l.
rewrite eq_sym_iff, eq_mul_0. tauto.
Qed.
@@ -227,306 +327,306 @@ Qed.
(** As soon as the divisor is strictly greater than 1,
the division is strictly decreasing. *)
-Lemma div_lt : forall a b, 0<a -> 1<b -> a/b < a.
-Proof. exact div_lt. Qed.
+Lemma quot_lt : forall a b, 0<a -> 1<b -> a÷b < a.
+Proof. exact NZQuot.div_lt. Qed.
(** [le] is compatible with a positive division. *)
-Lemma div_le_mono : forall a b c, 0<c -> a<=b -> a/c <= b/c.
+Lemma quot_le_mono : forall a b c, 0<c -> a<=b -> a÷c <= b÷c.
Proof.
-intros. pos_or_neg a. apply div_le_mono; auto.
+intros. pos_or_neg a. apply NZQuot.div_le_mono; auto.
pos_or_neg b. apply le_trans with 0.
- rewrite <- opp_nonneg_nonpos, <- div_opp_l by order.
- apply div_pos; order.
- apply div_pos; order.
-rewrite opp_le_mono in *. rewrite <- 2 div_opp_l by order.
- apply div_le_mono; intuition; order.
+ rewrite <- opp_nonneg_nonpos, <- quot_opp_l by order.
+ apply quot_pos; order.
+ apply quot_pos; order.
+rewrite opp_le_mono in *. rewrite <- 2 quot_opp_l by order.
+ apply NZQuot.div_le_mono; intuition; order.
Qed.
(** With this choice of division,
- rounding of div is always done toward zero: *)
+ rounding of quot is always done toward zero: *)
-Lemma mul_div_le : forall a b, 0<=a -> b~=0 -> 0 <= b*(a/b) <= a.
+Lemma mul_quot_le : forall a b, 0<=a -> b~=0 -> 0 <= b*(a÷b) <= a.
Proof.
intros. pos_or_neg b.
split.
-apply mul_nonneg_nonneg; [|apply div_pos]; order.
-apply mul_div_le; order.
-rewrite <- mul_opp_opp, <- div_opp_r by order.
+apply mul_nonneg_nonneg; [|apply quot_pos]; order.
+apply NZQuot.mul_div_le; order.
+rewrite <- mul_opp_opp, <- quot_opp_r by order.
split.
-apply mul_nonneg_nonneg; [|apply div_pos]; order.
-apply mul_div_le; order.
+apply mul_nonneg_nonneg; [|apply quot_pos]; order.
+apply NZQuot.mul_div_le; order.
Qed.
-Lemma mul_div_ge : forall a b, a<=0 -> b~=0 -> a <= b*(a/b) <= 0.
+Lemma mul_quot_ge : forall a b, a<=0 -> b~=0 -> a <= b*(a÷b) <= 0.
Proof.
intros.
-rewrite <- opp_nonneg_nonpos, opp_le_mono, <-mul_opp_r, <-div_opp_l by order.
+rewrite <- opp_nonneg_nonpos, opp_le_mono, <-mul_opp_r, <-quot_opp_l by order.
rewrite <- opp_nonneg_nonpos in *.
-destruct (mul_div_le (-a) b); tauto.
+destruct (mul_quot_le (-a) b); tauto.
Qed.
-(** For positive numbers, considering [S (a/b)] leads to an upper bound for [a] *)
+(** For positive numbers, considering [S (a÷b)] leads to an upper bound for [a] *)
-Lemma mul_succ_div_gt: forall a b, 0<=a -> 0<b -> a < b*(S (a/b)).
-Proof. exact mul_succ_div_gt. Qed.
+Lemma mul_succ_quot_gt: forall a b, 0<=a -> 0<b -> a < b*(S (a÷b)).
+Proof. exact NZQuot.mul_succ_div_gt. Qed.
(** Similar results with negative numbers *)
-Lemma mul_pred_div_lt: forall a b, a<=0 -> 0<b -> b*(P (a/b)) < a.
+Lemma mul_pred_quot_lt: forall a b, a<=0 -> 0<b -> b*(P (a÷b)) < a.
Proof.
intros.
-rewrite opp_lt_mono, <- mul_opp_r, opp_pred, <- div_opp_l by order.
+rewrite opp_lt_mono, <- mul_opp_r, opp_pred, <- quot_opp_l by order.
rewrite <- opp_nonneg_nonpos in *.
-now apply mul_succ_div_gt.
+now apply mul_succ_quot_gt.
Qed.
-Lemma mul_pred_div_gt: forall a b, 0<=a -> b<0 -> a < b*(P (a/b)).
+Lemma mul_pred_quot_gt: forall a b, 0<=a -> b<0 -> a < b*(P (a÷b)).
Proof.
intros.
-rewrite <- mul_opp_opp, opp_pred, <- div_opp_r by order.
+rewrite <- mul_opp_opp, opp_pred, <- quot_opp_r by order.
rewrite <- opp_pos_neg in *.
-now apply mul_succ_div_gt.
+now apply mul_succ_quot_gt.
Qed.
-Lemma mul_succ_div_lt: forall a b, a<=0 -> b<0 -> b*(S (a/b)) < a.
+Lemma mul_succ_quot_lt: forall a b, a<=0 -> b<0 -> b*(S (a÷b)) < a.
Proof.
intros.
-rewrite opp_lt_mono, <- mul_opp_l, <- div_opp_opp by order.
+rewrite opp_lt_mono, <- mul_opp_l, <- quot_opp_opp by order.
rewrite <- opp_nonneg_nonpos, <- opp_pos_neg in *.
-now apply mul_succ_div_gt.
+now apply mul_succ_quot_gt.
Qed.
-(** Inequality [mul_div_le] is exact iff the modulo is zero. *)
+(** Inequality [mul_quot_le] is exact iff the modulo is zero. *)
-Lemma div_exact : forall a b, b~=0 -> (a == b*(a/b) <-> a mod b == 0).
+Lemma quot_exact : forall a b, b~=0 -> (a == b*(a÷b) <-> a rem b == 0).
Proof.
-intros. rewrite mod_eq by order. rewrite sub_move_r; nzsimpl; tauto.
+intros. rewrite rem_eq by order. rewrite sub_move_r; nzsimpl; tauto.
Qed.
-(** Some additionnal inequalities about div. *)
+(** Some additionnal inequalities about quot. *)
-Theorem div_lt_upper_bound:
- forall a b q, 0<=a -> 0<b -> a < b*q -> a/b < q.
-Proof. exact div_lt_upper_bound. Qed.
+Theorem quot_lt_upper_bound:
+ forall a b q, 0<=a -> 0<b -> a < b*q -> a÷b < q.
+Proof. exact NZQuot.div_lt_upper_bound. Qed.
-Theorem div_le_upper_bound:
- forall a b q, 0<b -> a <= b*q -> a/b <= q.
+Theorem quot_le_upper_bound:
+ forall a b q, 0<b -> a <= b*q -> a÷b <= q.
Proof.
intros.
-rewrite <- (div_mul q b) by order.
-apply div_le_mono; trivial. now rewrite mul_comm.
+rewrite <- (quot_mul q b) by order.
+apply quot_le_mono; trivial. now rewrite mul_comm.
Qed.
-Theorem div_le_lower_bound:
- forall a b q, 0<b -> b*q <= a -> q <= a/b.
+Theorem quot_le_lower_bound:
+ forall a b q, 0<b -> b*q <= a -> q <= a÷b.
Proof.
intros.
-rewrite <- (div_mul q b) by order.
-apply div_le_mono; trivial. now rewrite mul_comm.
+rewrite <- (quot_mul q b) by order.
+apply quot_le_mono; trivial. now rewrite mul_comm.
Qed.
(** A division respects opposite monotonicity for the divisor *)
-Lemma div_le_compat_l: forall p q r, 0<=p -> 0<q<=r -> p/r <= p/q.
-Proof. exact div_le_compat_l. Qed.
+Lemma quot_le_compat_l: forall p q r, 0<=p -> 0<q<=r -> p÷r <= p÷q.
+Proof. exact NZQuot.div_le_compat_l. Qed.
-(** * Relations between usual operations and mod and div *)
+(** * Relations between usual operations and rem and quot *)
(** Unlike with other division conventions, some results here aren't
always valid, and need to be restricted. For instance
- [(a+b*c) mod c <> a mod c] for [a=9,b=-5,c=2] *)
+ [(a+b*c) rem c <> a rem c] for [a=9,b=-5,c=2] *)
-Lemma mod_add : forall a b c, c~=0 -> 0 <= (a+b*c)*a ->
- (a + b * c) mod c == a mod c.
+Lemma rem_add : forall a b c, c~=0 -> 0 <= (a+b*c)*a ->
+ (a + b * c) rem c == a rem c.
Proof.
-assert (forall a b c, c~=0 -> 0<=a -> 0<=a+b*c -> (a+b*c) mod c == a mod c).
- intros. pos_or_neg c. apply mod_add; order.
- rewrite <- (mod_opp_r a), <- (mod_opp_r (a+b*c)) by order.
+assert (forall a b c, c~=0 -> 0<=a -> 0<=a+b*c -> (a+b*c) rem c == a rem c).
+ intros. pos_or_neg c. apply NZQuot.mod_add; order.
+ rewrite <- (rem_opp_r a), <- (rem_opp_r (a+b*c)) by order.
rewrite <- mul_opp_opp in *.
- apply mod_add; order.
+ apply NZQuot.mod_add; order.
intros a b c Hc Habc.
destruct (le_0_mul _ _ Habc) as [(Habc',Ha)|(Habc',Ha)]. auto.
apply opp_inj. revert Ha Habc'.
rewrite <- 2 opp_nonneg_nonpos.
-rewrite <- 2 mod_opp_l, opp_add_distr, <- mul_opp_l by order. auto.
+rewrite <- 2 rem_opp_l, opp_add_distr, <- mul_opp_l by order. auto.
Qed.
-Lemma div_add : forall a b c, c~=0 -> 0 <= (a+b*c)*a ->
- (a + b * c) / c == a / c + b.
+Lemma quot_add : forall a b c, c~=0 -> 0 <= (a+b*c)*a ->
+ (a + b * c) ÷ c == a ÷ c + b.
Proof.
intros.
rewrite <- (mul_cancel_l _ _ c) by trivial.
-rewrite <- (add_cancel_r _ _ ((a+b*c) mod c)).
-rewrite <- div_mod, mod_add by trivial.
-now rewrite mul_add_distr_l, add_shuffle0, <-div_mod, mul_comm.
+rewrite <- (add_cancel_r _ _ ((a+b*c) rem c)).
+rewrite <- quot_rem, rem_add by trivial.
+now rewrite mul_add_distr_l, add_shuffle0, <-quot_rem, mul_comm.
Qed.
-Lemma div_add_l: forall a b c, b~=0 -> 0 <= (a*b+c)*c ->
- (a * b + c) / b == a + c / b.
+Lemma quot_add_l: forall a b c, b~=0 -> 0 <= (a*b+c)*c ->
+ (a * b + c) ÷ b == a + c ÷ b.
Proof.
- intros a b c. rewrite add_comm, (add_comm a). now apply div_add.
+ intros a b c. rewrite add_comm, (add_comm a). now apply quot_add.
Qed.
(** Cancellations. *)
-Lemma div_mul_cancel_r : forall a b c, b~=0 -> c~=0 ->
- (a*c)/(b*c) == a/b.
+Lemma quot_mul_cancel_r : forall a b c, b~=0 -> c~=0 ->
+ (a*c)÷(b*c) == a÷b.
Proof.
-assert (Aux1 : forall a b c, 0<=a -> 0<b -> c~=0 -> (a*c)/(b*c) == a/b).
- intros. pos_or_neg c. apply div_mul_cancel_r; order.
- rewrite <- div_opp_opp, <- 2 mul_opp_r. apply div_mul_cancel_r; order.
+assert (Aux1 : forall a b c, 0<=a -> 0<b -> c~=0 -> (a*c)÷(b*c) == a÷b).
+ intros. pos_or_neg c. apply NZQuot.div_mul_cancel_r; order.
+ rewrite <- quot_opp_opp, <- 2 mul_opp_r. apply NZQuot.div_mul_cancel_r; order.
rewrite <- neq_mul_0; intuition order.
-assert (Aux2 : forall a b c, 0<=a -> b~=0 -> c~=0 -> (a*c)/(b*c) == a/b).
+assert (Aux2 : forall a b c, 0<=a -> b~=0 -> c~=0 -> (a*c)÷(b*c) == a÷b).
intros. pos_or_neg b. apply Aux1; order.
- apply opp_inj. rewrite <- 2 div_opp_r, <- mul_opp_l; try order. apply Aux1; order.
+ apply opp_inj. rewrite <- 2 quot_opp_r, <- mul_opp_l; try order. apply Aux1; order.
rewrite <- neq_mul_0; intuition order.
intros. pos_or_neg a. apply Aux2; order.
-apply opp_inj. rewrite <- 2 div_opp_l, <- mul_opp_l; try order. apply Aux2; order.
+apply opp_inj. rewrite <- 2 quot_opp_l, <- mul_opp_l; try order. apply Aux2; order.
rewrite <- neq_mul_0; intuition order.
Qed.
-Lemma div_mul_cancel_l : forall a b c, b~=0 -> c~=0 ->
- (c*a)/(c*b) == a/b.
+Lemma quot_mul_cancel_l : forall a b c, b~=0 -> c~=0 ->
+ (c*a)÷(c*b) == a÷b.
Proof.
-intros. rewrite !(mul_comm c); now apply div_mul_cancel_r.
+intros. rewrite !(mul_comm c); now apply quot_mul_cancel_r.
Qed.
-Lemma mul_mod_distr_r: forall a b c, b~=0 -> c~=0 ->
- (a*c) mod (b*c) == (a mod b) * c.
+Lemma mul_rem_distr_r: forall a b c, b~=0 -> c~=0 ->
+ (a*c) rem (b*c) == (a rem b) * c.
Proof.
intros.
assert (b*c ~= 0) by (rewrite <- neq_mul_0; tauto).
-rewrite ! mod_eq by trivial.
-rewrite div_mul_cancel_r by order.
-now rewrite mul_sub_distr_r, <- !mul_assoc, (mul_comm (a/b) c).
+rewrite ! rem_eq by trivial.
+rewrite quot_mul_cancel_r by order.
+now rewrite mul_sub_distr_r, <- !mul_assoc, (mul_comm (a÷b) c).
Qed.
-Lemma mul_mod_distr_l: forall a b c, b~=0 -> c~=0 ->
- (c*a) mod (c*b) == c * (a mod b).
+Lemma mul_rem_distr_l: forall a b c, b~=0 -> c~=0 ->
+ (c*a) rem (c*b) == c * (a rem b).
Proof.
-intros; rewrite !(mul_comm c); now apply mul_mod_distr_r.
+intros; rewrite !(mul_comm c); now apply mul_rem_distr_r.
Qed.
(** Operations modulo. *)
-Theorem mod_mod: forall a n, n~=0 ->
- (a mod n) mod n == a mod n.
+Theorem rem_rem: forall a n, n~=0 ->
+ (a rem n) rem n == a rem n.
Proof.
-intros. pos_or_neg a; pos_or_neg n. apply mod_mod; order.
-rewrite <- ! (mod_opp_r _ n) by trivial. apply mod_mod; order.
-apply opp_inj. rewrite <- !mod_opp_l by order. apply mod_mod; order.
-apply opp_inj. rewrite <- !mod_opp_opp by order. apply mod_mod; order.
+intros. pos_or_neg a; pos_or_neg n. apply NZQuot.mod_mod; order.
+rewrite <- ! (rem_opp_r _ n) by trivial. apply NZQuot.mod_mod; order.
+apply opp_inj. rewrite <- !rem_opp_l by order. apply NZQuot.mod_mod; order.
+apply opp_inj. rewrite <- !rem_opp_opp by order. apply NZQuot.mod_mod; order.
Qed.
-Lemma mul_mod_idemp_l : forall a b n, n~=0 ->
- ((a mod n)*b) mod n == (a*b) mod n.
+Lemma mul_rem_idemp_l : forall a b n, n~=0 ->
+ ((a rem n)*b) rem n == (a*b) rem n.
Proof.
assert (Aux1 : forall a b n, 0<=a -> 0<=b -> n~=0 ->
- ((a mod n)*b) mod n == (a*b) mod n).
- intros. pos_or_neg n. apply mul_mod_idemp_l; order.
- rewrite <- ! (mod_opp_r _ n) by order. apply mul_mod_idemp_l; order.
+ ((a rem n)*b) rem n == (a*b) rem n).
+ intros. pos_or_neg n. apply NZQuot.mul_mod_idemp_l; order.
+ rewrite <- ! (rem_opp_r _ n) by order. apply NZQuot.mul_mod_idemp_l; order.
assert (Aux2 : forall a b n, 0<=a -> n~=0 ->
- ((a mod n)*b) mod n == (a*b) mod n).
+ ((a rem n)*b) rem n == (a*b) rem n).
intros. pos_or_neg b. now apply Aux1.
- apply opp_inj. rewrite <-2 mod_opp_l, <-2 mul_opp_r by order.
+ apply opp_inj. rewrite <-2 rem_opp_l, <-2 mul_opp_r by order.
apply Aux1; order.
intros a b n Hn. pos_or_neg a. now apply Aux2.
-apply opp_inj. rewrite <-2 mod_opp_l, <-2 mul_opp_l, <-mod_opp_l by order.
+apply opp_inj. rewrite <-2 rem_opp_l, <-2 mul_opp_l, <-rem_opp_l by order.
apply Aux2; order.
Qed.
-Lemma mul_mod_idemp_r : forall a b n, n~=0 ->
- (a*(b mod n)) mod n == (a*b) mod n.
+Lemma mul_rem_idemp_r : forall a b n, n~=0 ->
+ (a*(b rem n)) rem n == (a*b) rem n.
Proof.
-intros. rewrite !(mul_comm a). now apply mul_mod_idemp_l.
+intros. rewrite !(mul_comm a). now apply mul_rem_idemp_l.
Qed.
-Theorem mul_mod: forall a b n, n~=0 ->
- (a * b) mod n == ((a mod n) * (b mod n)) mod n.
+Theorem mul_rem: forall a b n, n~=0 ->
+ (a * b) rem n == ((a rem n) * (b rem n)) rem n.
Proof.
-intros. now rewrite mul_mod_idemp_l, mul_mod_idemp_r.
+intros. now rewrite mul_rem_idemp_l, mul_rem_idemp_r.
Qed.
(** addition and modulo
Generally speaking, unlike with other conventions, we don't have
- [(a+b) mod n = (a mod n + b mod n) mod n]
+ [(a+b) rem n = (a rem n + b rem n) rem n]
for any a and b.
- For instance, take (8 + (-10)) mod 3 = -2 whereas
- (8 mod 3 + (-10 mod 3)) mod 3 = 1.
+ For instance, take (8 + (-10)) rem 3 = -2 whereas
+ (8 rem 3 + (-10 rem 3)) rem 3 = 1.
*)
-Lemma add_mod_idemp_l : forall a b n, n~=0 -> 0 <= a*b ->
- ((a mod n)+b) mod n == (a+b) mod n.
+Lemma add_rem_idemp_l : forall a b n, n~=0 -> 0 <= a*b ->
+ ((a rem n)+b) rem n == (a+b) rem n.
Proof.
assert (Aux : forall a b n, 0<=a -> 0<=b -> n~=0 ->
- ((a mod n)+b) mod n == (a+b) mod n).
- intros. pos_or_neg n. apply add_mod_idemp_l; order.
- rewrite <- ! (mod_opp_r _ n) by order. apply add_mod_idemp_l; order.
+ ((a rem n)+b) rem n == (a+b) rem n).
+ intros. pos_or_neg n. apply NZQuot.add_mod_idemp_l; order.
+ rewrite <- ! (rem_opp_r _ n) by order. apply NZQuot.add_mod_idemp_l; order.
intros a b n Hn Hab. destruct (le_0_mul _ _ Hab) as [(Ha,Hb)|(Ha,Hb)].
now apply Aux.
-apply opp_inj. rewrite <-2 mod_opp_l, 2 opp_add_distr, <-mod_opp_l by order.
+apply opp_inj. rewrite <-2 rem_opp_l, 2 opp_add_distr, <-rem_opp_l by order.
rewrite <- opp_nonneg_nonpos in *.
now apply Aux.
Qed.
-Lemma add_mod_idemp_r : forall a b n, n~=0 -> 0 <= a*b ->
- (a+(b mod n)) mod n == (a+b) mod n.
+Lemma add_rem_idemp_r : forall a b n, n~=0 -> 0 <= a*b ->
+ (a+(b rem n)) rem n == (a+b) rem n.
Proof.
-intros. rewrite !(add_comm a). apply add_mod_idemp_l; trivial.
+intros. rewrite !(add_comm a). apply add_rem_idemp_l; trivial.
now rewrite mul_comm.
Qed.
-Theorem add_mod: forall a b n, n~=0 -> 0 <= a*b ->
- (a+b) mod n == (a mod n + b mod n) mod n.
+Theorem add_rem: forall a b n, n~=0 -> 0 <= a*b ->
+ (a+b) rem n == (a rem n + b rem n) rem n.
Proof.
-intros a b n Hn Hab. rewrite add_mod_idemp_l, add_mod_idemp_r; trivial.
+intros a b n Hn Hab. rewrite add_rem_idemp_l, add_rem_idemp_r; trivial.
reflexivity.
destruct (le_0_mul _ _ Hab) as [(Ha,Hb)|(Ha,Hb)];
- destruct (le_0_mul _ _ (mod_sign b n Hn)) as [(Hb',Hm)|(Hb',Hm)];
+ destruct (le_0_mul _ _ (rem_sign_mul b n Hn)) as [(Hb',Hm)|(Hb',Hm)];
auto using mul_nonneg_nonneg, mul_nonpos_nonpos.
- setoid_replace b with 0 by order. rewrite mod_0_l by order. nzsimpl; order.
- setoid_replace b with 0 by order. rewrite mod_0_l by order. nzsimpl; order.
+ setoid_replace b with 0 by order. rewrite rem_0_l by order. nzsimpl; order.
+ setoid_replace b with 0 by order. rewrite rem_0_l by order. nzsimpl; order.
Qed.
+(** Conversely, the following results need less restrictions here. *)
-(** Conversely, the following result needs less restrictions here. *)
-
-Lemma div_div : forall a b c, b~=0 -> c~=0 ->
- (a/b)/c == a/(b*c).
+Lemma quot_quot : forall a b c, b~=0 -> c~=0 ->
+ (a÷b)÷c == a÷(b*c).
Proof.
-assert (Aux1 : forall a b c, 0<=a -> 0<b -> c~=0 -> (a/b)/c == a/(b*c)).
- intros. pos_or_neg c. apply div_div; order.
- apply opp_inj. rewrite <- 2 div_opp_r, <- mul_opp_r; trivial.
- apply div_div; order.
+assert (Aux1 : forall a b c, 0<=a -> 0<b -> c~=0 -> (a÷b)÷c == a÷(b*c)).
+ intros. pos_or_neg c. apply NZQuot.div_div; order.
+ apply opp_inj. rewrite <- 2 quot_opp_r, <- mul_opp_r; trivial.
+ apply NZQuot.div_div; order.
rewrite <- neq_mul_0; intuition order.
-assert (Aux2 : forall a b c, 0<=a -> b~=0 -> c~=0 -> (a/b)/c == a/(b*c)).
+assert (Aux2 : forall a b c, 0<=a -> b~=0 -> c~=0 -> (a÷b)÷c == a÷(b*c)).
intros. pos_or_neg b. apply Aux1; order.
- apply opp_inj. rewrite <- div_opp_l, <- 2 div_opp_r, <- mul_opp_l; trivial.
+ apply opp_inj. rewrite <- quot_opp_l, <- 2 quot_opp_r, <- mul_opp_l; trivial.
apply Aux1; trivial.
rewrite <- neq_mul_0; intuition order.
intros. pos_or_neg a. apply Aux2; order.
-apply opp_inj. rewrite <- 3 div_opp_l; try order. apply Aux2; order.
+apply opp_inj. rewrite <- 3 quot_opp_l; try order. apply Aux2; order.
rewrite <- neq_mul_0. tauto.
Qed.
-(** A last inequality: *)
-
-Theorem div_mul_le:
- forall a b c, 0<=a -> 0<b -> 0<=c -> c*(a/b) <= (c*a)/b.
-Proof. exact div_mul_le. Qed.
-
-(** mod is related to divisibility *)
-
-Lemma mod_divides : forall a b, b~=0 ->
- (a mod b == 0 <-> exists c, a == b*c).
+Lemma mod_mul_r : forall a b c, b~=0 -> c~=0 ->
+ a rem (b*c) == a rem b + b*((a÷b) rem c).
Proof.
- intros a b Hb. split.
- intros Hab. exists (a/b). rewrite (div_mod a b Hb) at 1.
- rewrite Hab; now nzsimpl.
- intros (c,Hc). rewrite Hc, mul_comm. now apply mod_mul.
+ intros a b c Hb Hc.
+ apply add_cancel_l with (b*c*(a÷(b*c))).
+ rewrite <- quot_rem by (apply neq_mul_0; split; order).
+ rewrite <- quot_quot by trivial.
+ rewrite add_assoc, add_shuffle0, <- mul_assoc, <- mul_add_distr_l.
+ rewrite <- quot_rem by order.
+ apply quot_rem; order.
Qed.
-End ZDivPropFunct.
+(** A last inequality: *)
+
+Theorem quot_mul_le:
+ forall a b c, 0<=a -> 0<b -> 0<=c -> c*(a÷b) <= (c*a)÷b.
+Proof. exact NZQuot.div_mul_le. Qed.
+
+End ZQuotProp.
diff --git a/theories/Numbers/Integer/Abstract/ZGcd.v b/theories/Numbers/Integer/Abstract/ZGcd.v
new file mode 100644
index 00000000..404fc0c4
--- /dev/null
+++ b/theories/Numbers/Integer/Abstract/ZGcd.v
@@ -0,0 +1,274 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Properties of the greatest common divisor *)
+
+Require Import ZAxioms ZMulOrder ZSgnAbs NZGcd.
+
+Module Type ZGcdProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZSgnAbsProp A B).
+
+ Include NZGcdProp A A B.
+
+(** Results concerning divisibility*)
+
+Lemma divide_opp_l : forall n m, (-n | m) <-> (n | m).
+Proof.
+ intros n m. split; intros (p,Hp); exists (-p); rewrite Hp.
+ now rewrite mul_opp_l, mul_opp_r.
+ now rewrite mul_opp_opp.
+Qed.
+
+Lemma divide_opp_r : forall n m, (n | -m) <-> (n | m).
+Proof.
+ intros n m. split; intros (p,Hp); exists (-p).
+ now rewrite mul_opp_l, <- Hp, opp_involutive.
+ now rewrite Hp, mul_opp_l.
+Qed.
+
+Lemma divide_abs_l : forall n m, (abs n | m) <-> (n | m).
+Proof.
+ intros n m. destruct (abs_eq_or_opp n) as [H|H]; rewrite H.
+ easy. apply divide_opp_l.
+Qed.
+
+Lemma divide_abs_r : forall n m, (n | abs m) <-> (n | m).
+Proof.
+ intros n m. destruct (abs_eq_or_opp m) as [H|H]; rewrite H.
+ easy. apply divide_opp_r.
+Qed.
+
+Lemma divide_1_r_abs : forall n, (n | 1) -> abs n == 1.
+Proof.
+ intros n Hn. apply divide_1_r_nonneg. apply abs_nonneg.
+ now apply divide_abs_l.
+Qed.
+
+Lemma divide_1_r : forall n, (n | 1) -> n==1 \/ n==-1.
+Proof.
+ intros n (m,H). rewrite mul_comm in H. now apply eq_mul_1 with m.
+Qed.
+
+Lemma divide_antisym_abs : forall n m,
+ (n | m) -> (m | n) -> abs n == abs m.
+Proof.
+ intros. apply divide_antisym_nonneg; try apply abs_nonneg.
+ now apply divide_abs_l, divide_abs_r.
+ now apply divide_abs_l, divide_abs_r.
+Qed.
+
+Lemma divide_antisym : forall n m,
+ (n | m) -> (m | n) -> n == m \/ n == -m.
+Proof.
+ intros. now apply abs_eq_cases, divide_antisym_abs.
+Qed.
+
+Lemma divide_sub_r : forall n m p, (n | m) -> (n | p) -> (n | m - p).
+Proof.
+ intros n m p H H'. rewrite <- add_opp_r.
+ apply divide_add_r; trivial. now apply divide_opp_r.
+Qed.
+
+Lemma divide_add_cancel_r : forall n m p, (n | m) -> (n | m + p) -> (n | p).
+Proof.
+ intros n m p H H'. rewrite <- (add_simpl_l m p). now apply divide_sub_r.
+Qed.
+
+(** Properties of gcd *)
+
+Lemma gcd_opp_l : forall n m, gcd (-n) m == gcd n m.
+Proof.
+ intros. apply gcd_unique_alt; try apply gcd_nonneg.
+ intros. rewrite divide_opp_r. apply gcd_divide_iff.
+Qed.
+
+Lemma gcd_opp_r : forall n m, gcd n (-m) == gcd n m.
+Proof.
+ intros. now rewrite gcd_comm, gcd_opp_l, gcd_comm.
+Qed.
+
+Lemma gcd_abs_l : forall n m, gcd (abs n) m == gcd n m.
+Proof.
+ intros. destruct (abs_eq_or_opp n) as [H|H]; rewrite H.
+ easy. apply gcd_opp_l.
+Qed.
+
+Lemma gcd_abs_r : forall n m, gcd n (abs m) == gcd n m.
+Proof.
+ intros. now rewrite gcd_comm, gcd_abs_l, gcd_comm.
+Qed.
+
+Lemma gcd_0_l : forall n, gcd 0 n == abs n.
+Proof.
+ intros. rewrite <- gcd_abs_r. apply gcd_0_l_nonneg, abs_nonneg.
+Qed.
+
+Lemma gcd_0_r : forall n, gcd n 0 == abs n.
+Proof.
+ intros. now rewrite gcd_comm, gcd_0_l.
+Qed.
+
+Lemma gcd_diag : forall n, gcd n n == abs n.
+Proof.
+ intros. rewrite <- gcd_abs_l, <- gcd_abs_r.
+ apply gcd_diag_nonneg, abs_nonneg.
+Qed.
+
+Lemma gcd_add_mult_diag_r : forall n m p, gcd n (m+p*n) == gcd n m.
+Proof.
+ intros. apply gcd_unique_alt; try apply gcd_nonneg.
+ intros. rewrite gcd_divide_iff. split; intros (U,V); split; trivial.
+ apply divide_add_r; trivial. now apply divide_mul_r.
+ apply divide_add_cancel_r with (p*n); trivial.
+ now apply divide_mul_r. now rewrite add_comm.
+Qed.
+
+Lemma gcd_add_diag_r : forall n m, gcd n (m+n) == gcd n m.
+Proof.
+ intros n m. rewrite <- (mul_1_l n) at 2. apply gcd_add_mult_diag_r.
+Qed.
+
+Lemma gcd_sub_diag_r : forall n m, gcd n (m-n) == gcd n m.
+Proof.
+ intros n m. rewrite <- (mul_1_l n) at 2.
+ rewrite <- add_opp_r, <- mul_opp_l. apply gcd_add_mult_diag_r.
+Qed.
+
+Definition Bezout n m p := exists a b, a*n + b*m == p.
+
+Instance Bezout_wd : Proper (eq==>eq==>eq==>iff) Bezout.
+Proof.
+ unfold Bezout. intros x x' Hx y y' Hy z z' Hz.
+ setoid_rewrite Hx. setoid_rewrite Hy. now setoid_rewrite Hz.
+Qed.
+
+Lemma bezout_1_gcd : forall n m, Bezout n m 1 -> gcd n m == 1.
+Proof.
+ intros n m (q & r & H).
+ apply gcd_unique; trivial using divide_1_l, le_0_1.
+ intros p Hn Hm.
+ rewrite <- H. apply divide_add_r; now apply divide_mul_r.
+Qed.
+
+Lemma gcd_bezout : forall n m p, gcd n m == p -> Bezout n m p.
+Proof.
+ (* First, a version restricted to natural numbers *)
+ assert (aux : forall n, 0<=n -> forall m, 0<=m -> Bezout n m (gcd n m)).
+ intros n Hn; pattern n.
+ apply strong_right_induction with (z:=0); trivial.
+ unfold Bezout. solve_proper.
+ clear n Hn. intros n Hn IHn.
+ apply le_lteq in Hn; destruct Hn as [Hn|Hn].
+ intros m Hm; pattern m.
+ apply strong_right_induction with (z:=0); trivial.
+ unfold Bezout. solve_proper.
+ clear m Hm. intros m Hm IHm.
+ destruct (lt_trichotomy n m) as [LT|[EQ|LT]].
+ (* n < m *)
+ destruct (IHm (m-n)) as (a & b & EQ).
+ apply sub_nonneg; order.
+ now apply lt_sub_pos.
+ exists (a-b). exists b.
+ rewrite gcd_sub_diag_r in EQ. rewrite <- EQ.
+ rewrite mul_sub_distr_r, mul_sub_distr_l.
+ now rewrite add_sub_assoc, add_sub_swap.
+ (* n = m *)
+ rewrite EQ. rewrite gcd_diag_nonneg; trivial.
+ exists 1. exists 0. now nzsimpl.
+ (* m < n *)
+ destruct (IHn m Hm LT n) as (a & b & EQ). order.
+ exists b. exists a. now rewrite gcd_comm, <- EQ, add_comm.
+ (* n = 0 *)
+ intros m Hm. rewrite <- Hn, gcd_0_l_nonneg; trivial.
+ exists 0. exists 1. now nzsimpl.
+ (* Then we relax the positivity condition on n *)
+ assert (aux' : forall n m, 0<=m -> Bezout n m (gcd n m)).
+ intros n m Hm.
+ destruct (le_ge_cases 0 n). now apply aux.
+ assert (Hn' : 0 <= -n) by now apply opp_nonneg_nonpos.
+ destruct (aux (-n) Hn' m Hm) as (a & b & EQ).
+ exists (-a). exists b. now rewrite <- gcd_opp_l, <- EQ, mul_opp_r, mul_opp_l.
+ (* And finally we do the same for m *)
+ intros n m p Hp. rewrite <- Hp; clear Hp.
+ destruct (le_ge_cases 0 m). now apply aux'.
+ assert (Hm' : 0 <= -m) by now apply opp_nonneg_nonpos.
+ destruct (aux' n (-m) Hm') as (a & b & EQ).
+ exists a. exists (-b). now rewrite <- gcd_opp_r, <- EQ, mul_opp_r, mul_opp_l.
+Qed.
+
+Lemma gcd_mul_mono_l :
+ forall n m p, gcd (p * n) (p * m) == abs p * gcd n m.
+Proof.
+ intros n m p.
+ apply gcd_unique.
+ apply mul_nonneg_nonneg; trivial using gcd_nonneg, abs_nonneg.
+ destruct (gcd_divide_l n m) as (q,Hq).
+ rewrite Hq at 2. rewrite mul_assoc. apply mul_divide_mono_r.
+ rewrite <- (abs_sgn p) at 2. rewrite <- mul_assoc. apply divide_factor_l.
+ destruct (gcd_divide_r n m) as (q,Hq).
+ rewrite Hq at 2. rewrite mul_assoc. apply mul_divide_mono_r.
+ rewrite <- (abs_sgn p) at 2. rewrite <- mul_assoc. apply divide_factor_l.
+ intros q H H'.
+ destruct (gcd_bezout n m (gcd n m) (eq_refl _)) as (a & b & EQ).
+ rewrite <- EQ, <- sgn_abs, mul_add_distr_l. apply divide_add_r.
+ rewrite mul_shuffle2. now apply divide_mul_l.
+ rewrite mul_shuffle2. now apply divide_mul_l.
+Qed.
+
+Lemma gcd_mul_mono_l_nonneg :
+ forall n m p, 0<=p -> gcd (p*n) (p*m) == p * gcd n m.
+Proof.
+ intros. rewrite <- (abs_eq p) at 3; trivial. apply gcd_mul_mono_l.
+Qed.
+
+Lemma gcd_mul_mono_r :
+ forall n m p, gcd (n * p) (m * p) == gcd n m * abs p.
+Proof.
+ intros n m p. now rewrite !(mul_comm _ p), gcd_mul_mono_l, mul_comm.
+Qed.
+
+Lemma gcd_mul_mono_r_nonneg :
+ forall n m p, 0<=p -> gcd (n*p) (m*p) == gcd n m * p.
+Proof.
+ intros. rewrite <- (abs_eq p) at 3; trivial. apply gcd_mul_mono_r.
+Qed.
+
+Lemma gauss : forall n m p, (n | m * p) -> gcd n m == 1 -> (n | p).
+Proof.
+ intros n m p H G.
+ destruct (gcd_bezout n m 1 G) as (a & b & EQ).
+ rewrite <- (mul_1_l p), <- EQ, mul_add_distr_r.
+ apply divide_add_r. rewrite mul_shuffle0. apply divide_factor_r.
+ rewrite <- mul_assoc. now apply divide_mul_r.
+Qed.
+
+Lemma divide_mul_split : forall n m p, n ~= 0 -> (n | m * p) ->
+ exists q r, n == q*r /\ (q | m) /\ (r | p).
+Proof.
+ intros n m p Hn H.
+ assert (G := gcd_nonneg n m).
+ apply le_lteq in G; destruct G as [G|G].
+ destruct (gcd_divide_l n m) as (q,Hq).
+ exists (gcd n m). exists q.
+ split. now rewrite mul_comm.
+ split. apply gcd_divide_r.
+ destruct (gcd_divide_r n m) as (r,Hr).
+ rewrite Hr in H. rewrite Hq in H at 1.
+ rewrite mul_shuffle0 in H. apply mul_divide_cancel_r in H; [|order].
+ apply gauss with r; trivial.
+ apply mul_cancel_r with (gcd n m); [order|].
+ rewrite mul_1_l.
+ rewrite <- gcd_mul_mono_r_nonneg, <- Hq, <- Hr; order.
+ symmetry in G. apply gcd_eq_0 in G. destruct G as (Hn',_); order.
+Qed.
+
+(** TODO : more about rel_prime (i.e. gcd == 1), about prime ... *)
+
+End ZGcdProp.
diff --git a/theories/Numbers/Integer/Abstract/ZLcm.v b/theories/Numbers/Integer/Abstract/ZLcm.v
new file mode 100644
index 00000000..06af04d1
--- /dev/null
+++ b/theories/Numbers/Integer/Abstract/ZLcm.v
@@ -0,0 +1,471 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import ZAxioms ZMulOrder ZSgnAbs ZGcd ZDivTrunc ZDivFloor.
+
+(** * Least Common Multiple *)
+
+(** Unlike other functions around, we will define lcm below instead of
+ axiomatizing it. Indeed, there is no "prior art" about lcm in the
+ standard library to be compliant with, and the generic definition
+ of lcm via gcd is quite reasonable.
+
+ By the way, we also state here some combined properties of div/mod
+ and quot/rem and gcd.
+*)
+
+Module Type ZLcmProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZSgnAbsProp A B)
+ (Import D : ZDivProp A B C)
+ (Import E : ZQuotProp A B C)
+ (Import F : ZGcdProp A B C).
+
+(** The two notions of division are equal on non-negative numbers *)
+
+Lemma quot_div_nonneg : forall a b, 0<=a -> 0<b -> a÷b == a/b.
+Proof.
+ intros. apply div_unique_pos with (a rem b).
+ now apply rem_bound_pos.
+ apply quot_rem. order.
+Qed.
+
+Lemma rem_mod_nonneg : forall a b, 0<=a -> 0<b -> a rem b == a mod b.
+Proof.
+ intros. apply mod_unique_pos with (a÷b).
+ now apply rem_bound_pos.
+ apply quot_rem. order.
+Qed.
+
+(** We can use the sign rule to have an relation between divisions. *)
+
+Lemma quot_div : forall a b, b~=0 ->
+ a÷b == (sgn a)*(sgn b)*(abs a / abs b).
+Proof.
+ assert (AUX : forall a b, 0<b -> a÷b == (sgn a)*(sgn b)*(abs a / abs b)).
+ intros a b Hb. rewrite (sgn_pos b), (abs_eq b), mul_1_r by order.
+ destruct (lt_trichotomy 0 a) as [Ha|[Ha|Ha]].
+ rewrite sgn_pos, abs_eq, mul_1_l, quot_div_nonneg; order.
+ rewrite <- Ha, abs_0, sgn_0, quot_0_l, div_0_l, mul_0_l; order.
+ rewrite sgn_neg, abs_neq, mul_opp_l, mul_1_l, eq_opp_r, <-quot_opp_l
+ by order.
+ apply quot_div_nonneg; trivial. apply opp_nonneg_nonpos; order.
+ (* main *)
+ intros a b Hb.
+ apply neg_pos_cases in Hb. destruct Hb as [Hb|Hb]; [|now apply AUX].
+ rewrite <- (opp_involutive b) at 1. rewrite quot_opp_r.
+ rewrite AUX, abs_opp, sgn_opp, mul_opp_r, mul_opp_l, opp_involutive.
+ reflexivity.
+ now apply opp_pos_neg.
+ rewrite eq_opp_l, opp_0; order.
+Qed.
+
+Lemma rem_mod : forall a b, b~=0 ->
+ a rem b == (sgn a) * ((abs a) mod (abs b)).
+Proof.
+ intros a b Hb.
+ rewrite <- rem_abs_r by trivial.
+ assert (Hb' := proj2 (abs_pos b) Hb).
+ destruct (lt_trichotomy 0 a) as [Ha|[Ha|Ha]].
+ rewrite (abs_eq a), sgn_pos, mul_1_l, rem_mod_nonneg; order.
+ rewrite <- Ha, abs_0, sgn_0, mod_0_l, rem_0_l, mul_0_l; order.
+ rewrite sgn_neg, (abs_neq a), mul_opp_l, mul_1_l, eq_opp_r, <-rem_opp_l
+ by order.
+ apply rem_mod_nonneg; trivial. apply opp_nonneg_nonpos; order.
+Qed.
+
+(** Modulo and remainder are null at the same place,
+ and this correspond to the divisibility relation. *)
+
+Lemma mod_divide : forall a b, b~=0 -> (a mod b == 0 <-> (b|a)).
+Proof.
+ intros a b Hb. split.
+ intros Hab. exists (a/b). rewrite mul_comm.
+ rewrite (div_mod a b Hb) at 1. rewrite Hab; now nzsimpl.
+ intros (c,Hc). rewrite Hc. now apply mod_mul.
+Qed.
+
+Lemma rem_divide : forall a b, b~=0 -> (a rem b == 0 <-> (b|a)).
+Proof.
+ intros a b Hb. split.
+ intros Hab. exists (a÷b). rewrite mul_comm.
+ rewrite (quot_rem a b Hb) at 1. rewrite Hab; now nzsimpl.
+ intros (c,Hc). rewrite Hc. now apply rem_mul.
+Qed.
+
+Lemma rem_mod_eq_0 : forall a b, b~=0 -> (a rem b == 0 <-> a mod b == 0).
+Proof.
+ intros a b Hb. now rewrite mod_divide, rem_divide.
+Qed.
+
+(** When division is exact, div and quot agree *)
+
+Lemma quot_div_exact : forall a b, b~=0 -> (b|a) -> a÷b == a/b.
+Proof.
+ intros a b Hb H.
+ apply mul_cancel_l with b; trivial.
+ assert (H':=H).
+ apply rem_divide, quot_exact in H; trivial.
+ apply mod_divide, div_exact in H'; trivial.
+ now rewrite <-H,<-H'.
+Qed.
+
+Lemma divide_div_mul_exact : forall a b c, b~=0 -> (b|a) ->
+ (c*a)/b == c*(a/b).
+Proof.
+ intros a b c Hb H.
+ apply mul_cancel_l with b; trivial.
+ rewrite mul_assoc, mul_shuffle0.
+ assert (H':=H). apply mod_divide, div_exact in H'; trivial.
+ rewrite <- H', (mul_comm a c).
+ symmetry. apply div_exact; trivial.
+ apply mod_divide; trivial.
+ now apply divide_mul_r.
+Qed.
+
+Lemma divide_quot_mul_exact : forall a b c, b~=0 -> (b|a) ->
+ (c*a)÷b == c*(a÷b).
+Proof.
+ intros a b c Hb H.
+ rewrite 2 quot_div_exact; trivial.
+ apply divide_div_mul_exact; trivial.
+ now apply divide_mul_r.
+Qed.
+
+(** Gcd of divided elements, for exact divisions *)
+
+Lemma gcd_div_factor : forall a b c, 0<c -> (c|a) -> (c|b) ->
+ gcd (a/c) (b/c) == (gcd a b)/c.
+Proof.
+ intros a b c Hc Ha Hb.
+ apply mul_cancel_l with c; try order.
+ assert (H:=gcd_greatest _ _ _ Ha Hb).
+ apply mod_divide, div_exact in H; try order.
+ rewrite <- H.
+ rewrite <- gcd_mul_mono_l_nonneg; try order.
+ f_equiv; symmetry; apply div_exact; try order;
+ apply mod_divide; trivial; try order.
+Qed.
+
+Lemma gcd_quot_factor : forall a b c, 0<c -> (c|a) -> (c|b) ->
+ gcd (a÷c) (b÷c) == (gcd a b)÷c.
+Proof.
+ intros a b c Hc Ha Hb. rewrite !quot_div_exact; trivial; try order.
+ now apply gcd_div_factor. now apply gcd_greatest.
+Qed.
+
+Lemma gcd_div_gcd : forall a b g, g~=0 -> g == gcd a b ->
+ gcd (a/g) (b/g) == 1.
+Proof.
+ intros a b g NZ EQ. rewrite gcd_div_factor.
+ now rewrite <- EQ, div_same.
+ generalize (gcd_nonneg a b); order.
+ rewrite EQ; apply gcd_divide_l.
+ rewrite EQ; apply gcd_divide_r.
+Qed.
+
+Lemma gcd_quot_gcd : forall a b g, g~=0 -> g == gcd a b ->
+ gcd (a÷g) (b÷g) == 1.
+Proof.
+ intros a b g NZ EQ. rewrite !quot_div_exact; trivial.
+ now apply gcd_div_gcd.
+ rewrite EQ; apply gcd_divide_r.
+ rewrite EQ; apply gcd_divide_l.
+Qed.
+
+(** The following equality is crucial for Euclid algorithm *)
+
+Lemma gcd_mod : forall a b, b~=0 -> gcd (a mod b) b == gcd b a.
+Proof.
+ intros a b Hb. rewrite mod_eq; trivial.
+ rewrite <- add_opp_r, mul_comm, <- mul_opp_l.
+ rewrite (gcd_comm _ b).
+ apply gcd_add_mult_diag_r.
+Qed.
+
+Lemma gcd_rem : forall a b, b~=0 -> gcd (a rem b) b == gcd b a.
+Proof.
+ intros a b Hb. rewrite rem_eq; trivial.
+ rewrite <- add_opp_r, mul_comm, <- mul_opp_l.
+ rewrite (gcd_comm _ b).
+ apply gcd_add_mult_diag_r.
+Qed.
+
+(** We now define lcm thanks to gcd:
+
+ lcm a b = a * (b / gcd a b)
+ = (a / gcd a b) * b
+ = (a*b) / gcd a b
+
+ We had an abs in order to have an always-nonnegative lcm,
+ in the spirit of gcd. Nota: [lcm 0 0] should be 0, which
+ isn't garantee with the third equation above.
+*)
+
+Definition lcm a b := abs (a*(b/gcd a b)).
+
+Instance lcm_wd : Proper (eq==>eq==>eq) lcm.
+Proof. unfold lcm. solve_proper. Qed.
+
+Lemma lcm_equiv1 : forall a b, gcd a b ~= 0 ->
+ a * (b / gcd a b) == (a*b)/gcd a b.
+Proof.
+ intros a b H. rewrite divide_div_mul_exact; try easy. apply gcd_divide_r.
+Qed.
+
+Lemma lcm_equiv2 : forall a b, gcd a b ~= 0 ->
+ (a / gcd a b) * b == (a*b)/gcd a b.
+Proof.
+ intros a b H. rewrite 2 (mul_comm _ b).
+ rewrite divide_div_mul_exact; try easy. apply gcd_divide_l.
+Qed.
+
+Lemma gcd_div_swap : forall a b,
+ (a / gcd a b) * b == a * (b / gcd a b).
+Proof.
+ intros a b. destruct (eq_decidable (gcd a b) 0) as [EQ|NEQ].
+ apply gcd_eq_0 in EQ. destruct EQ as (EQ,EQ'). rewrite EQ, EQ'. now nzsimpl.
+ now rewrite lcm_equiv1, <-lcm_equiv2.
+Qed.
+
+Lemma divide_lcm_l : forall a b, (a | lcm a b).
+Proof.
+ unfold lcm. intros a b. apply divide_abs_r, divide_factor_l.
+Qed.
+
+Lemma divide_lcm_r : forall a b, (b | lcm a b).
+Proof.
+ unfold lcm. intros a b. apply divide_abs_r. rewrite <- gcd_div_swap.
+ apply divide_factor_r.
+Qed.
+
+Lemma divide_div : forall a b c, a~=0 -> (a|b) -> (b|c) -> (b/a|c/a).
+Proof.
+ intros a b c Ha Hb (c',Hc). exists c'.
+ now rewrite <- divide_div_mul_exact, <- Hc.
+Qed.
+
+Lemma lcm_least : forall a b c,
+ (a | c) -> (b | c) -> (lcm a b | c).
+Proof.
+ intros a b c Ha Hb. unfold lcm. apply divide_abs_l.
+ destruct (eq_decidable (gcd a b) 0) as [EQ|NEQ].
+ apply gcd_eq_0 in EQ. destruct EQ as (EQ,EQ'). rewrite EQ in *. now nzsimpl.
+ assert (Ga := gcd_divide_l a b).
+ assert (Gb := gcd_divide_r a b).
+ set (g:=gcd a b) in *.
+ assert (Ha' := divide_div g a c NEQ Ga Ha).
+ assert (Hb' := divide_div g b c NEQ Gb Hb).
+ destruct Ha' as (a',Ha'). rewrite Ha', mul_comm in Hb'.
+ apply gauss in Hb'; [|apply gcd_div_gcd; unfold g; trivial using gcd_comm].
+ destruct Hb' as (b',Hb').
+ exists b'.
+ rewrite mul_shuffle3, <- Hb'.
+ rewrite (proj2 (div_exact c g NEQ)).
+ rewrite Ha', mul_shuffle3, (mul_comm a a'). f_equiv.
+ symmetry. apply div_exact; trivial.
+ apply mod_divide; trivial.
+ apply mod_divide; trivial. transitivity a; trivial.
+Qed.
+
+Lemma lcm_nonneg : forall a b, 0 <= lcm a b.
+Proof.
+ intros a b. unfold lcm. apply abs_nonneg.
+Qed.
+
+Lemma lcm_comm : forall a b, lcm a b == lcm b a.
+Proof.
+ intros a b. unfold lcm. rewrite (gcd_comm b), (mul_comm b).
+ now rewrite <- gcd_div_swap.
+Qed.
+
+Lemma lcm_divide_iff : forall n m p,
+ (lcm n m | p) <-> (n | p) /\ (m | p).
+Proof.
+ intros. split. split.
+ transitivity (lcm n m); trivial using divide_lcm_l.
+ transitivity (lcm n m); trivial using divide_lcm_r.
+ intros (H,H'). now apply lcm_least.
+Qed.
+
+Lemma lcm_unique : forall n m p,
+ 0<=p -> (n|p) -> (m|p) ->
+ (forall q, (n|q) -> (m|q) -> (p|q)) ->
+ lcm n m == p.
+Proof.
+ intros n m p Hp Hn Hm H.
+ apply divide_antisym_nonneg; trivial. apply lcm_nonneg.
+ now apply lcm_least.
+ apply H. apply divide_lcm_l. apply divide_lcm_r.
+Qed.
+
+Lemma lcm_unique_alt : forall n m p, 0<=p ->
+ (forall q, (p|q) <-> (n|q) /\ (m|q)) ->
+ lcm n m == p.
+Proof.
+ intros n m p Hp H.
+ apply lcm_unique; trivial.
+ apply H, divide_refl.
+ apply H, divide_refl.
+ intros. apply H. now split.
+Qed.
+
+Lemma lcm_assoc : forall n m p, lcm n (lcm m p) == lcm (lcm n m) p.
+Proof.
+ intros. apply lcm_unique_alt; try apply lcm_nonneg.
+ intros. now rewrite !lcm_divide_iff, and_assoc.
+Qed.
+
+Lemma lcm_0_l : forall n, lcm 0 n == 0.
+Proof.
+ intros. apply lcm_unique; trivial. order.
+ apply divide_refl.
+ apply divide_0_r.
+Qed.
+
+Lemma lcm_0_r : forall n, lcm n 0 == 0.
+Proof.
+ intros. now rewrite lcm_comm, lcm_0_l.
+Qed.
+
+Lemma lcm_1_l_nonneg : forall n, 0<=n -> lcm 1 n == n.
+Proof.
+ intros. apply lcm_unique; trivial using divide_1_l, le_0_1, divide_refl.
+Qed.
+
+Lemma lcm_1_r_nonneg : forall n, 0<=n -> lcm n 1 == n.
+Proof.
+ intros. now rewrite lcm_comm, lcm_1_l_nonneg.
+Qed.
+
+Lemma lcm_diag_nonneg : forall n, 0<=n -> lcm n n == n.
+Proof.
+ intros. apply lcm_unique; trivial using divide_refl.
+Qed.
+
+Lemma lcm_eq_0 : forall n m, lcm n m == 0 <-> n == 0 \/ m == 0.
+Proof.
+ intros. split.
+ intros EQ.
+ apply eq_mul_0.
+ apply divide_0_l. rewrite <- EQ. apply lcm_least.
+ apply divide_factor_l. apply divide_factor_r.
+ destruct 1 as [EQ|EQ]; rewrite EQ. apply lcm_0_l. apply lcm_0_r.
+Qed.
+
+Lemma divide_lcm_eq_r : forall n m, 0<=m -> (n|m) -> lcm n m == m.
+Proof.
+ intros n m Hm H. apply lcm_unique_alt; trivial.
+ intros q. split. split; trivial. now transitivity m.
+ now destruct 1.
+Qed.
+
+Lemma divide_lcm_iff : forall n m, 0<=m -> ((n|m) <-> lcm n m == m).
+Proof.
+ intros n m Hn. split. now apply divide_lcm_eq_r.
+ intros EQ. rewrite <- EQ. apply divide_lcm_l.
+Qed.
+
+Lemma lcm_opp_l : forall n m, lcm (-n) m == lcm n m.
+Proof.
+ intros. apply lcm_unique_alt; try apply lcm_nonneg.
+ intros. rewrite divide_opp_l. apply lcm_divide_iff.
+Qed.
+
+Lemma lcm_opp_r : forall n m, lcm n (-m) == lcm n m.
+Proof.
+ intros. now rewrite lcm_comm, lcm_opp_l, lcm_comm.
+Qed.
+
+Lemma lcm_abs_l : forall n m, lcm (abs n) m == lcm n m.
+Proof.
+ intros. destruct (abs_eq_or_opp n) as [H|H]; rewrite H.
+ easy. apply lcm_opp_l.
+Qed.
+
+Lemma lcm_abs_r : forall n m, lcm n (abs m) == lcm n m.
+Proof.
+ intros. now rewrite lcm_comm, lcm_abs_l, lcm_comm.
+Qed.
+
+Lemma lcm_1_l : forall n, lcm 1 n == abs n.
+Proof.
+ intros. rewrite <- lcm_abs_r. apply lcm_1_l_nonneg, abs_nonneg.
+Qed.
+
+Lemma lcm_1_r : forall n, lcm n 1 == abs n.
+Proof.
+ intros. now rewrite lcm_comm, lcm_1_l.
+Qed.
+
+Lemma lcm_diag : forall n, lcm n n == abs n.
+Proof.
+ intros. rewrite <- lcm_abs_l, <- lcm_abs_r.
+ apply lcm_diag_nonneg, abs_nonneg.
+Qed.
+
+Lemma lcm_mul_mono_l :
+ forall n m p, lcm (p * n) (p * m) == abs p * lcm n m.
+Proof.
+ intros n m p.
+ destruct (eq_decidable p 0) as [Hp|Hp].
+ rewrite Hp. nzsimpl. rewrite lcm_0_l, abs_0. now nzsimpl.
+ destruct (eq_decidable (gcd n m) 0) as [Hg|Hg].
+ apply gcd_eq_0 in Hg. destruct Hg as (Hn,Hm); rewrite Hn, Hm.
+ nzsimpl. rewrite lcm_0_l. now nzsimpl.
+ unfold lcm.
+ rewrite gcd_mul_mono_l.
+ rewrite !abs_mul, mul_assoc. f_equiv.
+ rewrite <- (abs_sgn p) at 1. rewrite <- mul_assoc.
+ rewrite div_mul_cancel_l; trivial.
+ rewrite divide_div_mul_exact; trivial. rewrite abs_mul.
+ rewrite <- (sgn_abs (sgn p)), sgn_sgn.
+ destruct (sgn_spec p) as [(_,EQ)|[(EQ,_)|(_,EQ)]].
+ rewrite EQ. now nzsimpl. order.
+ rewrite EQ. rewrite mul_opp_l, mul_opp_r, opp_involutive. now nzsimpl.
+ apply gcd_divide_r.
+ contradict Hp. now apply abs_0_iff.
+Qed.
+
+Lemma lcm_mul_mono_l_nonneg :
+ forall n m p, 0<=p -> lcm (p*n) (p*m) == p * lcm n m.
+Proof.
+ intros. rewrite <- (abs_eq p) at 3; trivial. apply lcm_mul_mono_l.
+Qed.
+
+Lemma lcm_mul_mono_r :
+ forall n m p, lcm (n * p) (m * p) == lcm n m * abs p.
+Proof.
+ intros n m p. now rewrite !(mul_comm _ p), lcm_mul_mono_l, mul_comm.
+Qed.
+
+Lemma lcm_mul_mono_r_nonneg :
+ forall n m p, 0<=p -> lcm (n*p) (m*p) == lcm n m * p.
+Proof.
+ intros. rewrite <- (abs_eq p) at 3; trivial. apply lcm_mul_mono_r.
+Qed.
+
+Lemma gcd_1_lcm_mul : forall n m, n~=0 -> m~=0 ->
+ (gcd n m == 1 <-> lcm n m == abs (n*m)).
+Proof.
+ intros n m Hn Hm. split; intros H.
+ unfold lcm. rewrite H. now rewrite div_1_r.
+ unfold lcm in *.
+ rewrite !abs_mul in H. apply mul_cancel_l in H; [|now rewrite abs_0_iff].
+ assert (H' := gcd_divide_r n m).
+ assert (Hg : gcd n m ~= 0) by (red; rewrite gcd_eq_0; destruct 1; order).
+ apply mod_divide in H'; trivial. apply div_exact in H'; trivial.
+ assert (m / gcd n m ~=0) by (contradict Hm; rewrite H', Hm; now nzsimpl).
+ rewrite <- (mul_1_l (abs (_/_))) in H.
+ rewrite H' in H at 3. rewrite abs_mul in H.
+ apply mul_cancel_r in H; [|now rewrite abs_0_iff].
+ rewrite abs_eq in H. order. apply gcd_nonneg.
+Qed.
+
+End ZLcmProp.
diff --git a/theories/Numbers/Integer/Abstract/ZLt.v b/theories/Numbers/Integer/Abstract/ZLt.v
index 57be0f0e..3a8e1f38 100644
--- a/theories/Numbers/Integer/Abstract/ZLt.v
+++ b/theories/Numbers/Integer/Abstract/ZLt.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZLt.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export ZMul.
-Module ZOrderPropFunct (Import Z : ZAxiomsSig').
-Include ZMulPropFunct Z.
+Module ZOrderProp (Import Z : ZAxiomsMiniSig').
+Include ZMulProp Z.
(** Instances of earlier theorems for m == 0 *)
@@ -70,12 +68,12 @@ Qed.
Theorem lt_lt_pred : forall n m, n < m -> P n < m.
Proof.
-intros; apply <- lt_pred_le; now apply lt_le_incl.
+intros; apply lt_pred_le; now apply lt_le_incl.
Qed.
Theorem le_le_pred : forall n m, n <= m -> P n <= m.
Proof.
-intros; apply lt_le_incl; now apply <- lt_pred_le.
+intros; apply lt_le_incl; now apply lt_pred_le.
Qed.
Theorem lt_pred_lt : forall n m, n < P m -> n < m.
@@ -85,7 +83,7 @@ Qed.
Theorem le_pred_lt : forall n m, n <= P m -> n <= m.
Proof.
-intros; apply lt_le_incl; now apply <- lt_le_pred.
+intros; apply lt_le_incl; now apply lt_le_pred.
Qed.
Theorem pred_lt_mono : forall n m, n < m <-> P n < P m.
@@ -123,12 +121,12 @@ Proof.
intro; apply lt_neq; apply lt_pred_l.
Qed.
-Theorem lt_n1_r : forall n m, n < m -> m < 0 -> n < -(1).
+Theorem lt_m1_r : forall n m, n < m -> m < 0 -> n < -1.
Proof.
-intros n m H1 H2. apply -> lt_le_pred in H2.
-setoid_replace (P 0) with (-(1)) in H2. now apply lt_le_trans with m.
-apply <- eq_opp_r. now rewrite opp_pred, opp_0.
+intros n m H1 H2. apply lt_le_pred in H2.
+setoid_replace (P 0) with (-1) in H2. now apply lt_le_trans with m.
+apply eq_opp_r. now rewrite one_succ, opp_pred, opp_0.
Qed.
-End ZOrderPropFunct.
+End ZOrderProp.
diff --git a/theories/Numbers/Integer/Abstract/ZMaxMin.v b/theories/Numbers/Integer/Abstract/ZMaxMin.v
new file mode 100644
index 00000000..4e653fee
--- /dev/null
+++ b/theories/Numbers/Integer/Abstract/ZMaxMin.v
@@ -0,0 +1,179 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import ZAxioms ZMulOrder GenericMinMax.
+
+(** * Properties of minimum and maximum specific to integer numbers *)
+
+Module Type ZMaxMinProp (Import Z : ZAxiomsMiniSig').
+Include ZMulOrderProp Z.
+
+(** The following results are concrete instances of [max_monotone]
+ and similar lemmas. *)
+
+(** Succ *)
+
+Lemma succ_max_distr : forall n m, S (max n m) == max (S n) (S m).
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?succ_le_mono.
+Qed.
+
+Lemma succ_min_distr : forall n m, S (min n m) == min (S n) (S m).
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?succ_le_mono.
+Qed.
+
+(** Pred *)
+
+Lemma pred_max_distr : forall n m, P (max n m) == max (P n) (P m).
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?pred_le_mono.
+Qed.
+
+Lemma pred_min_distr : forall n m, P (min n m) == min (P n) (P m).
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?pred_le_mono.
+Qed.
+
+(** Add *)
+
+Lemma add_max_distr_l : forall n m p, max (p + n) (p + m) == p + max n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?add_le_mono_l.
+Qed.
+
+Lemma add_max_distr_r : forall n m p, max (n + p) (m + p) == max n m + p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?add_le_mono_r.
+Qed.
+
+Lemma add_min_distr_l : forall n m p, min (p + n) (p + m) == p + min n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?add_le_mono_l.
+Qed.
+
+Lemma add_min_distr_r : forall n m p, min (n + p) (m + p) == min n m + p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?add_le_mono_r.
+Qed.
+
+(** Opp *)
+
+Lemma opp_max_distr : forall n m, -(max n m) == min (-n) (-m).
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite max_r by trivial. symmetry. apply min_r. now rewrite <- opp_le_mono.
+ rewrite max_l by trivial. symmetry. apply min_l. now rewrite <- opp_le_mono.
+Qed.
+
+Lemma opp_min_distr : forall n m, -(min n m) == max (-n) (-m).
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite min_l by trivial. symmetry. apply max_l. now rewrite <- opp_le_mono.
+ rewrite min_r by trivial. symmetry. apply max_r. now rewrite <- opp_le_mono.
+Qed.
+
+(** Sub *)
+
+Lemma sub_max_distr_l : forall n m p, max (p - n) (p - m) == p - min n m.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite min_l by trivial. apply max_l. now rewrite <- sub_le_mono_l.
+ rewrite min_r by trivial. apply max_r. now rewrite <- sub_le_mono_l.
+Qed.
+
+Lemma sub_max_distr_r : forall n m p, max (n - p) (m - p) == max n m - p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; try order; now apply sub_le_mono_r.
+Qed.
+
+Lemma sub_min_distr_l : forall n m p, min (p - n) (p - m) == p - max n m.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite max_r by trivial. apply min_r. now rewrite <- sub_le_mono_l.
+ rewrite max_l by trivial. apply min_l. now rewrite <- sub_le_mono_l.
+Qed.
+
+Lemma sub_min_distr_r : forall n m p, min (n - p) (m - p) == min n m - p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; try order; now apply sub_le_mono_r.
+Qed.
+
+(** Mul *)
+
+Lemma mul_max_distr_nonneg_l : forall n m p, 0 <= p ->
+ max (p * n) (p * m) == p * max n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; try order; now apply mul_le_mono_nonneg_l.
+Qed.
+
+Lemma mul_max_distr_nonneg_r : forall n m p, 0 <= p ->
+ max (n * p) (m * p) == max n m * p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; try order; now apply mul_le_mono_nonneg_r.
+Qed.
+
+Lemma mul_min_distr_nonneg_l : forall n m p, 0 <= p ->
+ min (p * n) (p * m) == p * min n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; try order; now apply mul_le_mono_nonneg_l.
+Qed.
+
+Lemma mul_min_distr_nonneg_r : forall n m p, 0 <= p ->
+ min (n * p) (m * p) == min n m * p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; try order; now apply mul_le_mono_nonneg_r.
+Qed.
+
+Lemma mul_max_distr_nonpos_l : forall n m p, p <= 0 ->
+ max (p * n) (p * m) == p * min n m.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite min_l by trivial. rewrite max_l. reflexivity. now apply mul_le_mono_nonpos_l.
+ rewrite min_r by trivial. rewrite max_r. reflexivity. now apply mul_le_mono_nonpos_l.
+Qed.
+
+Lemma mul_max_distr_nonpos_r : forall n m p, p <= 0 ->
+ max (n * p) (m * p) == min n m * p.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite min_l by trivial. rewrite max_l. reflexivity. now apply mul_le_mono_nonpos_r.
+ rewrite min_r by trivial. rewrite max_r. reflexivity. now apply mul_le_mono_nonpos_r.
+Qed.
+
+Lemma mul_min_distr_nonpos_l : forall n m p, p <= 0 ->
+ min (p * n) (p * m) == p * max n m.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite max_r by trivial. rewrite min_r. reflexivity. now apply mul_le_mono_nonpos_l.
+ rewrite max_l by trivial. rewrite min_l. reflexivity. now apply mul_le_mono_nonpos_l.
+Qed.
+
+Lemma mul_min_distr_nonpos_r : forall n m p, p <= 0 ->
+ min (n * p) (m * p) == max n m * p.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite max_r by trivial. rewrite min_r. reflexivity. now apply mul_le_mono_nonpos_r.
+ rewrite max_l by trivial. rewrite min_l. reflexivity. now apply mul_le_mono_nonpos_r.
+Qed.
+
+End ZMaxMinProp.
diff --git a/theories/Numbers/Integer/Abstract/ZMul.v b/theories/Numbers/Integer/Abstract/ZMul.v
index 83dc0e10..36f9c3d5 100644
--- a/theories/Numbers/Integer/Abstract/ZMul.v
+++ b/theories/Numbers/Integer/Abstract/ZMul.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZMul.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export ZAdd.
-Module ZMulPropFunct (Import Z : ZAxiomsSig').
-Include ZAddPropFunct Z.
+Module ZMulProp (Import Z : ZAxiomsMiniSig').
+Include ZAddProp Z.
(** A note on naming: right (correspondingly, left) distributivity
happens when the sum is multiplied by a number on the right
@@ -41,7 +39,7 @@ Qed.
Theorem mul_opp_l : forall n m, (- n) * m == - (n * m).
Proof.
-intros n m. apply -> add_move_0_r.
+intros n m. apply add_move_0_r.
now rewrite <- mul_add_distr_r, add_opp_diag_l, mul_0_l.
Qed.
@@ -55,6 +53,11 @@ Proof.
intros n m; now rewrite mul_opp_l, mul_opp_r, opp_involutive.
Qed.
+Theorem mul_opp_comm : forall n m, (- n) * m == n * (- m).
+Proof.
+intros n m. now rewrite mul_opp_l, <- mul_opp_r.
+Qed.
+
Theorem mul_sub_distr_l : forall n m p, n * (m - p) == n * m - n * p.
Proof.
intros n m p. do 2 rewrite <- add_opp_r. rewrite mul_add_distr_l.
@@ -67,6 +70,6 @@ intros n m p; rewrite (mul_comm (n - m) p), (mul_comm n p), (mul_comm m p);
now apply mul_sub_distr_l.
Qed.
-End ZMulPropFunct.
+End ZMulProp.
diff --git a/theories/Numbers/Integer/Abstract/ZMulOrder.v b/theories/Numbers/Integer/Abstract/ZMulOrder.v
index 06a5d168..d0d64faa 100644
--- a/theories/Numbers/Integer/Abstract/ZMulOrder.v
+++ b/theories/Numbers/Integer/Abstract/ZMulOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,14 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZMulOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export ZAddOrder.
-Module Type ZMulOrderPropFunct (Import Z : ZAxiomsSig').
-Include ZAddOrderPropFunct Z.
-
-Local Notation "- 1" := (-(1)).
+Module Type ZMulOrderProp (Import Z : ZAxiomsMiniSig').
+Include ZAddOrderProp Z.
Theorem mul_lt_mono_nonpos :
forall n m p q, m <= 0 -> n < m -> q <= 0 -> p < q -> m * q < n * p.
@@ -94,18 +90,11 @@ Qed.
Notation mul_nonpos := le_mul_0 (only parsing).
-Theorem le_0_square : forall n, 0 <= n * n.
-Proof.
-intro n; destruct (neg_nonneg_cases n).
-apply lt_le_incl; now apply mul_neg_neg.
-now apply mul_nonneg_nonneg.
-Qed.
-
-Notation square_nonneg := le_0_square (only parsing).
+Notation le_0_square := square_nonneg (only parsing).
Theorem nlt_square_0 : forall n, ~ n * n < 0.
Proof.
-intros n H. apply -> lt_nge in H. apply H. apply square_nonneg.
+intros n H. apply lt_nge in H. apply H. apply square_nonneg.
Qed.
Theorem square_lt_mono_nonpos : forall n m, n <= 0 -> m < n -> n * n < m * m.
@@ -120,42 +109,38 @@ Qed.
Theorem square_lt_simpl_nonpos : forall n m, m <= 0 -> n * n < m * m -> m < n.
Proof.
-intros n m H1 H2. destruct (le_gt_cases n 0).
-destruct (lt_ge_cases m n).
-assumption. assert (F : m * m <= n * n) by now apply square_le_mono_nonpos.
-apply -> le_ngt in F. false_hyp H2 F.
-now apply le_lt_trans with 0.
+intros n m H1 H2. destruct (le_gt_cases n 0); [|order].
+destruct (lt_ge_cases m n) as [LE|GT]; trivial.
+apply square_le_mono_nonpos in GT; order.
Qed.
Theorem square_le_simpl_nonpos : forall n m, m <= 0 -> n * n <= m * m -> m <= n.
Proof.
-intros n m H1 H2. destruct (le_gt_cases n 0).
-destruct (le_gt_cases m n).
-assumption. assert (F : m * m < n * n) by now apply square_lt_mono_nonpos.
-apply -> lt_nge in F. false_hyp H2 F.
-apply lt_le_incl; now apply le_lt_trans with 0.
+intros n m H1 H2. destruct (le_gt_cases n 0); [|order].
+destruct (le_gt_cases m n) as [LE|GT]; trivial.
+apply square_lt_mono_nonpos in GT; order.
Qed.
Theorem lt_1_mul_neg : forall n m, n < -1 -> m < 0 -> 1 < n * m.
Proof.
-intros n m H1 H2. apply -> (mul_lt_mono_neg_r m) in H1.
-apply <- opp_pos_neg in H2. rewrite mul_opp_l, mul_1_l in H1.
+intros n m H1 H2. apply (mul_lt_mono_neg_r m) in H1.
+apply opp_pos_neg in H2. rewrite mul_opp_l, mul_1_l in H1.
now apply lt_1_l with (- m).
assumption.
Qed.
-Theorem lt_mul_n1_neg : forall n m, 1 < n -> m < 0 -> n * m < -1.
+Theorem lt_mul_m1_neg : forall n m, 1 < n -> m < 0 -> n * m < -1.
Proof.
-intros n m H1 H2. apply -> (mul_lt_mono_neg_r m) in H1.
-rewrite mul_1_l in H1. now apply lt_n1_r with m.
+intros n m H1 H2. apply (mul_lt_mono_neg_r m) in H1.
+rewrite mul_1_l in H1. now apply lt_m1_r with m.
assumption.
Qed.
-Theorem lt_mul_n1_pos : forall n m, n < -1 -> 0 < m -> n * m < -1.
+Theorem lt_mul_m1_pos : forall n m, n < -1 -> 0 < m -> n * m < -1.
Proof.
-intros n m H1 H2. apply -> (mul_lt_mono_pos_r m) in H1.
+intros n m H1 H2. apply (mul_lt_mono_pos_r m) in H1.
rewrite mul_opp_l, mul_1_l in H1.
-apply <- opp_neg_pos in H2. now apply lt_n1_r with (- m).
+apply opp_neg_pos in H2. now apply lt_m1_r with (- m).
assumption.
Qed.
@@ -163,39 +148,33 @@ Theorem lt_1_mul_l : forall n m, 1 < n ->
n * m < -1 \/ n * m == 0 \/ 1 < n * m.
Proof.
intros n m H; destruct (lt_trichotomy m 0) as [H1 | [H1 | H1]].
-left. now apply lt_mul_n1_neg.
+left. now apply lt_mul_m1_neg.
right; left; now rewrite H1, mul_0_r.
right; right; now apply lt_1_mul_pos.
Qed.
-Theorem lt_n1_mul_r : forall n m, n < -1 ->
+Theorem lt_m1_mul_r : forall n m, n < -1 ->
n * m < -1 \/ n * m == 0 \/ 1 < n * m.
Proof.
intros n m H; destruct (lt_trichotomy m 0) as [H1 | [H1 | H1]].
right; right. now apply lt_1_mul_neg.
right; left; now rewrite H1, mul_0_r.
-left. now apply lt_mul_n1_pos.
+left. now apply lt_mul_m1_pos.
Qed.
Theorem eq_mul_1 : forall n m, n * m == 1 -> n == 1 \/ n == -1.
Proof.
-assert (F : ~ 1 < -1).
-intro H.
-assert (H1 : -1 < 0). apply <- opp_neg_pos. apply lt_succ_diag_r.
-assert (H2 : 1 < 0) by now apply lt_trans with (-1).
-false_hyp H2 nlt_succ_diag_l.
+assert (F := lt_m1_0).
zero_pos_neg n.
-intros m H; rewrite mul_0_l in H; false_hyp H neq_succ_diag_r.
-intros n H; split; apply <- le_succ_l in H; le_elim H.
-intros m H1; apply (lt_1_mul_l n m) in H.
-rewrite H1 in H; destruct H as [H | [H | H]].
-false_hyp H F. false_hyp H neq_succ_diag_l. false_hyp H lt_irrefl.
-intros; now left.
-intros m H1; apply (lt_1_mul_l n m) in H. rewrite mul_opp_l in H1;
-apply -> eq_opp_l in H1. rewrite H1 in H; destruct H as [H | [H | H]].
-false_hyp H lt_irrefl. apply -> eq_opp_l in H. rewrite opp_0 in H.
-false_hyp H neq_succ_diag_l. false_hyp H F.
-intros; right; symmetry; now apply opp_wd.
+(* n = 0 *)
+intros m. nzsimpl. now left.
+(* 0 < n, proving P n /\ P (-n) *)
+intros n Hn. rewrite <- le_succ_l, <- one_succ in Hn.
+le_elim Hn; split; intros m H.
+destruct (lt_1_mul_l n m) as [|[|]]; order'.
+rewrite mul_opp_l, eq_opp_l in H. destruct (lt_1_mul_l n m) as [|[|]]; order'.
+now left.
+intros; right. now f_equiv.
Qed.
Theorem lt_mul_diag_l : forall n m, n < 0 -> (1 < m <-> n * m < n).
@@ -229,5 +208,9 @@ apply mul_lt_mono_nonneg.
now apply lt_le_incl. assumption. apply le_0_1. assumption.
Qed.
-End ZMulOrderPropFunct.
+(** Alternative name : *)
+
+Definition mul_eq_1 := eq_mul_1.
+
+End ZMulOrderProp.
diff --git a/theories/Numbers/Integer/Abstract/ZParity.v b/theories/Numbers/Integer/Abstract/ZParity.v
new file mode 100644
index 00000000..b364ec3f
--- /dev/null
+++ b/theories/Numbers/Integer/Abstract/ZParity.v
@@ -0,0 +1,52 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import Bool ZMulOrder NZParity.
+
+(** Some more properties of [even] and [odd]. *)
+
+Module Type ZParityProp (Import Z : ZAxiomsSig')
+ (Import ZP : ZMulOrderProp Z).
+
+Include NZParityProp Z Z ZP.
+
+Lemma odd_pred : forall n, odd (P n) = even n.
+Proof.
+ intros. rewrite <- (succ_pred n) at 2. symmetry. apply even_succ.
+Qed.
+
+Lemma even_pred : forall n, even (P n) = odd n.
+Proof.
+ intros. rewrite <- (succ_pred n) at 2. symmetry. apply odd_succ.
+Qed.
+
+Lemma even_opp : forall n, even (-n) = even n.
+Proof.
+ assert (H : forall n, Even n -> Even (-n)).
+ intros n (m,H). exists (-m). rewrite mul_opp_r. now f_equiv.
+ intros. rewrite eq_iff_eq_true, !even_spec.
+ split. rewrite <- (opp_involutive n) at 2. apply H.
+ apply H.
+Qed.
+
+Lemma odd_opp : forall n, odd (-n) = odd n.
+Proof.
+ intros. rewrite <- !negb_even. now rewrite even_opp.
+Qed.
+
+Lemma even_sub : forall n m, even (n-m) = Bool.eqb (even n) (even m).
+Proof.
+ intros. now rewrite <- add_opp_r, even_add, even_opp.
+Qed.
+
+Lemma odd_sub : forall n m, odd (n-m) = xorb (odd n) (odd m).
+Proof.
+ intros. now rewrite <- add_opp_r, odd_add, odd_opp.
+Qed.
+
+End ZParityProp.
diff --git a/theories/Numbers/Integer/Abstract/ZPow.v b/theories/Numbers/Integer/Abstract/ZPow.v
new file mode 100644
index 00000000..53d84dce
--- /dev/null
+++ b/theories/Numbers/Integer/Abstract/ZPow.v
@@ -0,0 +1,124 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Properties of the power function *)
+
+Require Import Bool ZAxioms ZMulOrder ZParity ZSgnAbs NZPow.
+
+Module Type ZPowProp
+ (Import A : ZAxiomsSig')
+ (Import B : ZMulOrderProp A)
+ (Import C : ZParityProp A B)
+ (Import D : ZSgnAbsProp A B).
+
+ Include NZPowProp A A B.
+
+(** Parity of power *)
+
+Lemma even_pow : forall a b, 0<b -> even (a^b) = even a.
+Proof.
+ intros a b Hb. apply lt_ind with (4:=Hb). solve_proper.
+ now nzsimpl.
+ clear b Hb. intros b Hb IH. nzsimpl; [|order].
+ rewrite even_mul, IH. now destruct (even a).
+Qed.
+
+Lemma odd_pow : forall a b, 0<b -> odd (a^b) = odd a.
+Proof.
+ intros. now rewrite <- !negb_even, even_pow.
+Qed.
+
+(** Properties of power of negative numbers *)
+
+Lemma pow_opp_even : forall a b, Even b -> (-a)^b == a^b.
+Proof.
+ intros a b (c,H). rewrite H.
+ destruct (le_gt_cases 0 c).
+ rewrite 2 pow_mul_r by order'.
+ rewrite 2 pow_2_r.
+ now rewrite mul_opp_opp.
+ assert (2*c < 0) by (apply mul_pos_neg; order').
+ now rewrite !pow_neg_r.
+Qed.
+
+Lemma pow_opp_odd : forall a b, Odd b -> (-a)^b == -(a^b).
+Proof.
+ intros a b (c,H). rewrite H.
+ destruct (le_gt_cases 0 c) as [LE|GT].
+ assert (0 <= 2*c) by (apply mul_nonneg_nonneg; order').
+ rewrite add_1_r, !pow_succ_r; trivial.
+ rewrite pow_opp_even by (now exists c).
+ apply mul_opp_l.
+ apply double_above in GT. rewrite mul_0_r in GT.
+ rewrite !pow_neg_r by trivial. now rewrite opp_0.
+Qed.
+
+Lemma pow_even_abs : forall a b, Even b -> a^b == (abs a)^b.
+Proof.
+ intros. destruct (abs_eq_or_opp a) as [EQ|EQ]; rewrite EQ.
+ reflexivity.
+ symmetry. now apply pow_opp_even.
+Qed.
+
+Lemma pow_even_nonneg : forall a b, Even b -> 0 <= a^b.
+Proof.
+ intros. rewrite pow_even_abs by trivial.
+ apply pow_nonneg, abs_nonneg.
+Qed.
+
+Lemma pow_odd_abs_sgn : forall a b, Odd b -> a^b == sgn a * (abs a)^b.
+Proof.
+ intros a b H.
+ destruct (sgn_spec a) as [(LT,EQ)|[(EQ',EQ)|(LT,EQ)]]; rewrite EQ.
+ nzsimpl.
+ rewrite abs_eq; order.
+ rewrite <- EQ'. nzsimpl.
+ destruct (le_gt_cases 0 b).
+ apply pow_0_l.
+ assert (b~=0) by (contradict H; now rewrite H, <-odd_spec, odd_0).
+ order.
+ now rewrite pow_neg_r.
+ rewrite abs_neq by order.
+ rewrite pow_opp_odd; trivial.
+ now rewrite mul_opp_opp, mul_1_l.
+Qed.
+
+Lemma pow_odd_sgn : forall a b, 0<=b -> Odd b -> sgn (a^b) == sgn a.
+Proof.
+ intros a b Hb H.
+ destruct (sgn_spec a) as [(LT,EQ)|[(EQ',EQ)|(LT,EQ)]]; rewrite EQ.
+ apply sgn_pos. apply pow_pos_nonneg; trivial.
+ rewrite <- EQ'. rewrite pow_0_l. apply sgn_0.
+ assert (b~=0) by (contradict H; now rewrite H, <-odd_spec, odd_0).
+ order.
+ apply sgn_neg.
+ rewrite <- (opp_involutive a). rewrite pow_opp_odd by trivial.
+ apply opp_neg_pos.
+ apply pow_pos_nonneg; trivial.
+ now apply opp_pos_neg.
+Qed.
+
+Lemma abs_pow : forall a b, abs (a^b) == (abs a)^b.
+Proof.
+ intros a b.
+ destruct (Even_or_Odd b).
+ rewrite pow_even_abs by trivial.
+ apply abs_eq, pow_nonneg, abs_nonneg.
+ rewrite pow_odd_abs_sgn by trivial.
+ rewrite abs_mul.
+ destruct (lt_trichotomy 0 a) as [Ha|[Ha|Ha]].
+ rewrite (sgn_pos a), (abs_eq 1), mul_1_l by order'.
+ apply abs_eq, pow_nonneg, abs_nonneg.
+ rewrite <- Ha, sgn_0, abs_0, mul_0_l.
+ symmetry. apply pow_0_l'. intro Hb. rewrite Hb in H.
+ apply (Even_Odd_False 0); trivial. exists 0; now nzsimpl.
+ rewrite (sgn_neg a), abs_opp, (abs_eq 1), mul_1_l by order'.
+ apply abs_eq, pow_nonneg, abs_nonneg.
+Qed.
+
+End ZPowProp.
diff --git a/theories/Numbers/Integer/Abstract/ZProperties.v b/theories/Numbers/Integer/Abstract/ZProperties.v
index ae7c3209..c0455196 100644
--- a/theories/Numbers/Integer/Abstract/ZProperties.v
+++ b/theories/Numbers/Integer/Abstract/ZProperties.v
@@ -1,24 +1,19 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: ZProperties.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
+Require Export ZAxioms ZMaxMin ZSgnAbs ZParity ZPow ZDivTrunc ZDivFloor
+ ZGcd ZLcm NZLog NZSqrt ZBits.
-Require Export ZAxioms ZMulOrder ZSgnAbs.
-
-(** This functor summarizes all known facts about Z.
- For the moment it is only an alias to [ZMulOrderPropFunct], which
- subsumes all others, plus properties of [sgn] and [abs].
-*)
-
-Module Type ZPropSig (Z:ZAxiomsExtSig) :=
- ZMulOrderPropFunct Z <+ ZSgnAbsPropSig Z.
-
-Module ZPropFunct (Z:ZAxiomsExtSig) <: ZPropSig Z.
- Include ZPropSig Z.
-End ZPropFunct.
+(** This functor summarizes all known facts about Z. *)
+Module Type ZProp (Z:ZAxiomsSig) :=
+ ZMaxMinProp Z <+ ZSgnAbsProp Z <+ ZParityProp Z <+ ZPowProp Z
+ <+ NZSqrtProp Z Z <+ NZSqrtUpProp Z Z
+ <+ NZLog2Prop Z Z Z <+ NZLog2UpProp Z Z Z
+ <+ ZDivProp Z <+ ZQuotProp Z <+ ZGcdProp Z <+ ZLcmProp Z
+ <+ ZBitsProp Z.
diff --git a/theories/Numbers/Integer/Abstract/ZSgnAbs.v b/theories/Numbers/Integer/Abstract/ZSgnAbs.v
index cecaa6a3..b2f6cc84 100644
--- a/theories/Numbers/Integer/Abstract/ZSgnAbs.v
+++ b/theories/Numbers/Integer/Abstract/ZSgnAbs.v
@@ -1,25 +1,19 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-Require Export ZMulOrder.
+(** Properties of [abs] and [sgn] *)
-(** An axiomatization of [abs]. *)
-
-Module Type HasAbs(Import Z : ZAxiomsSig').
- Parameter Inline abs : t -> t.
- Axiom abs_eq : forall n, 0<=n -> abs n == n.
- Axiom abs_neq : forall n, n<=0 -> abs n == -n.
-End HasAbs.
+Require Import ZMulOrder.
(** Since we already have [max], we could have defined [abs]. *)
-Module GenericAbs (Import Z : ZAxiomsSig')
- (Import ZP : ZMulOrderPropFunct Z) <: HasAbs Z.
+Module GenericAbs (Import Z : ZAxiomsMiniSig')
+ (Import ZP : ZMulOrderProp Z) <: HasAbs Z.
Definition abs n := max n (-n).
Lemma abs_eq : forall n, 0<=n -> abs n == n.
Proof.
@@ -35,37 +29,28 @@ Module GenericAbs (Import Z : ZAxiomsSig')
Qed.
End GenericAbs.
-(** An Axiomatization of [sgn]. *)
-
-Module Type HasSgn (Import Z : ZAxiomsSig').
- Parameter Inline sgn : t -> t.
- Axiom sgn_null : forall n, n==0 -> sgn n == 0.
- Axiom sgn_pos : forall n, 0<n -> sgn n == 1.
- Axiom sgn_neg : forall n, n<0 -> sgn n == -(1).
-End HasSgn.
-
(** We can deduce a [sgn] function from a [compare] function *)
-Module Type ZDecAxiomsSig := ZAxiomsSig <+ HasCompare.
-Module Type ZDecAxiomsSig' := ZAxiomsSig' <+ HasCompare.
+Module Type ZDecAxiomsSig := ZAxiomsMiniSig <+ HasCompare.
+Module Type ZDecAxiomsSig' := ZAxiomsMiniSig' <+ HasCompare.
Module Type GenericSgn (Import Z : ZDecAxiomsSig')
- (Import ZP : ZMulOrderPropFunct Z) <: HasSgn Z.
+ (Import ZP : ZMulOrderProp Z) <: HasSgn Z.
Definition sgn n :=
- match compare 0 n with Eq => 0 | Lt => 1 | Gt => -(1) end.
+ match compare 0 n with Eq => 0 | Lt => 1 | Gt => -1 end.
Lemma sgn_null : forall n, n==0 -> sgn n == 0.
Proof. unfold sgn; intros. destruct (compare_spec 0 n); order. Qed.
Lemma sgn_pos : forall n, 0<n -> sgn n == 1.
Proof. unfold sgn; intros. destruct (compare_spec 0 n); order. Qed.
- Lemma sgn_neg : forall n, n<0 -> sgn n == -(1).
+ Lemma sgn_neg : forall n, n<0 -> sgn n == -1.
Proof. unfold sgn; intros. destruct (compare_spec 0 n); order. Qed.
End GenericSgn.
-Module Type ZAxiomsExtSig := ZAxiomsSig <+ HasAbs <+ HasSgn.
-Module Type ZAxiomsExtSig' := ZAxiomsSig' <+ HasAbs <+ HasSgn.
-Module Type ZSgnAbsPropSig (Import Z : ZAxiomsExtSig')
- (Import ZP : ZMulOrderPropFunct Z).
+(** Derived properties of [abs] and [sgn] *)
+
+Module Type ZSgnAbsProp (Import Z : ZAxiomsSig')
+ (Import ZP : ZMulOrderProp Z).
Ltac destruct_max n :=
destruct (le_ge_cases 0 n);
@@ -183,6 +168,28 @@ Proof.
rewrite EQn, EQ, opp_inj_wd, eq_opp_l, or_comm. apply abs_eq_or_opp.
Qed.
+Lemma abs_lt : forall a b, abs a < b <-> -b < a < b.
+Proof.
+ intros a b.
+ destruct (abs_spec a) as [[LE EQ]|[LT EQ]]; rewrite EQ; clear EQ.
+ split; try split; try destruct 1; try order.
+ apply lt_le_trans with 0; trivial. apply opp_neg_pos; order.
+ rewrite opp_lt_mono, opp_involutive.
+ split; try split; try destruct 1; try order.
+ apply lt_le_trans with 0; trivial. apply opp_nonpos_nonneg; order.
+Qed.
+
+Lemma abs_le : forall a b, abs a <= b <-> -b <= a <= b.
+Proof.
+ intros a b.
+ destruct (abs_spec a) as [[LE EQ]|[LT EQ]]; rewrite EQ; clear EQ.
+ split; try split; try destruct 1; try order.
+ apply le_trans with 0; trivial. apply opp_nonpos_nonneg; order.
+ rewrite opp_le_mono, opp_involutive.
+ split; try split; try destruct 1; try order.
+ apply le_trans with 0. order. apply opp_nonpos_nonneg; order.
+Qed.
+
(** Triangular inequality *)
Lemma abs_triangle : forall n m, abs (n + m) <= abs n + abs m.
@@ -249,7 +256,7 @@ Qed.
Lemma sgn_spec : forall n,
0 < n /\ sgn n == 1 \/
0 == n /\ sgn n == 0 \/
- 0 > n /\ sgn n == -(1).
+ 0 > n /\ sgn n == -1.
Proof.
intros n.
destruct_sgn n; [left|right;left|right;right]; auto with relations.
@@ -264,7 +271,7 @@ Lemma sgn_pos_iff : forall n, sgn n == 1 <-> 0<n.
Proof.
split; try apply sgn_pos. destruct_sgn n; auto.
intros. elim (lt_neq 0 1); auto. apply lt_0_1.
- intros. elim (lt_neq (-(1)) 1); auto.
+ intros. elim (lt_neq (-1) 1); auto.
apply lt_trans with 0. rewrite opp_neg_pos. apply lt_0_1. apply lt_0_1.
Qed.
@@ -272,16 +279,16 @@ Lemma sgn_null_iff : forall n, sgn n == 0 <-> n==0.
Proof.
split; try apply sgn_null. destruct_sgn n; auto with relations.
intros. elim (lt_neq 0 1); auto with relations. apply lt_0_1.
- intros. elim (lt_neq (-(1)) 0); auto.
+ intros. elim (lt_neq (-1) 0); auto.
rewrite opp_neg_pos. apply lt_0_1.
Qed.
-Lemma sgn_neg_iff : forall n, sgn n == -(1) <-> n<0.
+Lemma sgn_neg_iff : forall n, sgn n == -1 <-> n<0.
Proof.
split; try apply sgn_neg. destruct_sgn n; auto with relations.
- intros. elim (lt_neq (-(1)) 1); auto with relations.
+ intros. elim (lt_neq (-1) 1); auto with relations.
apply lt_trans with 0. rewrite opp_neg_pos. apply lt_0_1. apply lt_0_1.
- intros. elim (lt_neq (-(1)) 0); auto with relations.
+ intros. elim (lt_neq (-1) 0); auto with relations.
rewrite opp_neg_pos. apply lt_0_1.
Qed.
@@ -343,6 +350,15 @@ Proof.
rewrite eq_opp_l. apply abs_neq. now apply lt_le_incl.
Qed.
-End ZSgnAbsPropSig.
+Lemma sgn_sgn : forall x, sgn (sgn x) == sgn x.
+Proof.
+ intros.
+ destruct (sgn_spec x) as [(LT,EQ)|[(EQ',EQ)|(LT,EQ)]]; rewrite EQ.
+ apply sgn_pos, lt_0_1.
+ now apply sgn_null.
+ apply sgn_neg. rewrite opp_neg_pos. apply lt_0_1.
+Qed.
+
+End ZSgnAbsProp.
diff --git a/theories/Numbers/Integer/BigZ/BigZ.v b/theories/Numbers/Integer/BigZ/BigZ.v
index 7df8909f..443777f5 100644
--- a/theories/Numbers/Integer/BigZ/BigZ.v
+++ b/theories/Numbers/Integer/BigZ/BigZ.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: BigZ.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export BigN.
Require Import ZProperties ZDivFloor ZSig ZSigZAxioms ZMake.
@@ -21,77 +19,59 @@ Require Import ZProperties ZDivFloor ZSig ZSigZAxioms ZMake.
- [ZMake.Make BigN] provides the operations and basic specs w.r.t. ZArith
- [ZTypeIsZAxioms] shows (mainly) that these operations implement
the interface [ZAxioms]
- - [ZPropSig] adds all generic properties derived from [ZAxioms]
- - [ZDivPropFunct] provides generic properties of [div] and [mod]
- ("Floor" variant)
+ - [ZProp] adds all generic properties derived from [ZAxioms]
- [MinMax*Properties] provides properties of [min] and [max]
*)
+Delimit Scope bigZ_scope with bigZ.
-Module BigZ <: ZType <: OrderedTypeFull <: TotalOrder :=
- ZMake.Make BigN <+ ZTypeIsZAxioms
- <+ !ZPropSig <+ !ZDivPropFunct <+ HasEqBool2Dec
- <+ !MinMaxLogicalProperties <+ !MinMaxDecProperties.
+Module BigZ <: ZType <: OrderedTypeFull <: TotalOrder.
+ Include ZMake.Make BigN [scope abstract_scope to bigZ_scope].
+ Bind Scope bigZ_scope with t t_.
+ Include ZTypeIsZAxioms
+ <+ ZProp [no inline]
+ <+ HasEqBool2Dec [no inline]
+ <+ MinMaxLogicalProperties [no inline]
+ <+ MinMaxDecProperties [no inline].
+End BigZ.
-(** Notations about [BigZ] *)
+(** For precision concerning the above scope handling, see comment in BigN *)
-Notation bigZ := BigZ.t.
+(** Notations about [BigZ] *)
-Delimit Scope bigZ_scope with bigZ.
-Bind Scope bigZ_scope with bigZ.
-Bind Scope bigZ_scope with BigZ.t.
-Bind Scope bigZ_scope with BigZ.t_.
-(* Bind Scope has no retroactive effect, let's declare scopes by hand. *)
-Arguments Scope BigZ.Pos [bigN_scope].
-Arguments Scope BigZ.Neg [bigN_scope].
-Arguments Scope BigZ.to_Z [bigZ_scope].
-Arguments Scope BigZ.succ [bigZ_scope].
-Arguments Scope BigZ.pred [bigZ_scope].
-Arguments Scope BigZ.opp [bigZ_scope].
-Arguments Scope BigZ.square [bigZ_scope].
-Arguments Scope BigZ.add [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.sub [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.mul [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.div [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.eq [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.lt [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.le [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.eq [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.compare [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.min [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.max [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.eq_bool [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.power_pos [bigZ_scope positive_scope].
-Arguments Scope BigZ.power [bigZ_scope N_scope].
-Arguments Scope BigZ.sqrt [bigZ_scope].
-Arguments Scope BigZ.div_eucl [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.modulo [bigZ_scope bigZ_scope].
-Arguments Scope BigZ.gcd [bigZ_scope bigZ_scope].
+Local Open Scope bigZ_scope.
+Notation bigZ := BigZ.t.
+Bind Scope bigZ_scope with bigZ BigZ.t BigZ.t_.
+Arguments BigZ.Pos _%bigN.
+Arguments BigZ.Neg _%bigN.
Local Notation "0" := BigZ.zero : bigZ_scope.
Local Notation "1" := BigZ.one : bigZ_scope.
+Local Notation "2" := BigZ.two : bigZ_scope.
Infix "+" := BigZ.add : bigZ_scope.
Infix "-" := BigZ.sub : bigZ_scope.
Notation "- x" := (BigZ.opp x) : bigZ_scope.
Infix "*" := BigZ.mul : bigZ_scope.
Infix "/" := BigZ.div : bigZ_scope.
-Infix "^" := BigZ.power : bigZ_scope.
+Infix "^" := BigZ.pow : bigZ_scope.
Infix "?=" := BigZ.compare : bigZ_scope.
+Infix "=?" := BigZ.eqb (at level 70, no associativity) : bigZ_scope.
+Infix "<=?" := BigZ.leb (at level 70, no associativity) : bigZ_scope.
+Infix "<?" := BigZ.ltb (at level 70, no associativity) : bigZ_scope.
Infix "==" := BigZ.eq (at level 70, no associativity) : bigZ_scope.
-Notation "x != y" := (~x==y)%bigZ (at level 70, no associativity) : bigZ_scope.
+Notation "x != y" := (~x==y) (at level 70, no associativity) : bigZ_scope.
Infix "<" := BigZ.lt : bigZ_scope.
Infix "<=" := BigZ.le : bigZ_scope.
-Notation "x > y" := (BigZ.lt y x)(only parsing) : bigZ_scope.
-Notation "x >= y" := (BigZ.le y x)(only parsing) : bigZ_scope.
-Notation "x < y < z" := (x<y /\ y<z)%bigZ : bigZ_scope.
-Notation "x < y <= z" := (x<y /\ y<=z)%bigZ : bigZ_scope.
-Notation "x <= y < z" := (x<=y /\ y<z)%bigZ : bigZ_scope.
-Notation "x <= y <= z" := (x<=y /\ y<=z)%bigZ : bigZ_scope.
+Notation "x > y" := (y < x) (only parsing) : bigZ_scope.
+Notation "x >= y" := (y <= x) (only parsing) : bigZ_scope.
+Notation "x < y < z" := (x<y /\ y<z) : bigZ_scope.
+Notation "x < y <= z" := (x<y /\ y<=z) : bigZ_scope.
+Notation "x <= y < z" := (x<=y /\ y<z) : bigZ_scope.
+Notation "x <= y <= z" := (x<=y /\ y<=z) : bigZ_scope.
Notation "[ i ]" := (BigZ.to_Z i) : bigZ_scope.
-Infix "mod" := BigZ.modulo (at level 40, no associativity) : bigN_scope.
-
-Local Open Scope bigZ_scope.
+Infix "mod" := BigZ.modulo (at level 40, no associativity) : bigZ_scope.
+Infix "÷" := BigZ.quot (at level 40, left associativity) : bigZ_scope.
(** Some additional results about [BigZ] *)
@@ -135,24 +115,26 @@ symmetry. apply BigZ.add_opp_r.
exact BigZ.add_opp_diag_r.
Qed.
-Lemma BigZeqb_correct : forall x y, BigZ.eq_bool x y = true -> x==y.
+Lemma BigZeqb_correct : forall x y, (x =? y) = true -> x==y.
Proof. now apply BigZ.eqb_eq. Qed.
-Lemma BigZpower : power_theory 1 BigZ.mul BigZ.eq (@id N) BigZ.power.
+Definition BigZ_of_N n := BigZ.of_Z (Z_of_N n).
+
+Lemma BigZpower : power_theory 1 BigZ.mul BigZ.eq BigZ_of_N BigZ.pow.
Proof.
constructor.
-intros. red. rewrite BigZ.spec_power. unfold id.
-destruct Zpower_theory as [EQ]. rewrite EQ.
+intros. unfold BigZ.eq, BigZ_of_N. rewrite BigZ.spec_pow, BigZ.spec_of_Z.
+rewrite Zpower_theory.(rpow_pow_N).
destruct n; simpl. reflexivity.
induction p; simpl; intros; BigZ.zify; rewrite ?IHp; auto.
Qed.
Lemma BigZdiv : div_theory BigZ.eq BigZ.add BigZ.mul (@id _)
- (fun a b => if BigZ.eq_bool b 0 then (0,a) else BigZ.div_eucl a b).
+ (fun a b => if b =? 0 then (0,a) else BigZ.div_eucl a b).
Proof.
constructor. unfold id. intros a b.
BigZ.zify.
-generalize (Zeq_bool_if [b] 0); destruct (Zeq_bool [b] 0).
+case Z.eqb_spec.
BigZ.zify. auto with zarith.
intros NEQ.
generalize (BigZ.spec_div_eucl a b).
@@ -170,6 +152,7 @@ Ltac isBigZcst t :=
| BigZ.Neg ?t => isBigNcst t
| BigZ.zero => constr:true
| BigZ.one => constr:true
+ | BigZ.two => constr:true
| BigZ.minus_one => constr:true
| _ => constr:false
end.
@@ -180,16 +163,25 @@ Ltac BigZcst t :=
| false => constr:NotConstant
end.
+Ltac BigZ_to_N t :=
+ match t with
+ | BigZ.Pos ?t => BigN_to_N t
+ | BigZ.zero => constr:0%N
+ | BigZ.one => constr:1%N
+ | BigZ.two => constr:2%N
+ | _ => constr:NotConstant
+ end.
+
(** Registration for the "ring" tactic *)
Add Ring BigZr : BigZring
(decidable BigZeqb_correct,
constants [BigZcst],
- power_tac BigZpower [Ncst],
+ power_tac BigZpower [BigZ_to_N],
div BigZdiv).
Section TestRing.
-Let test : forall x y, 1 + x*y + x^2 + 1 == 1*1 + 1 + y*x + 1*x*x.
+Let test : forall x y, 1 + x*y + x^2 + 1 == 1*1 + 1 + (y + 1*x)*x.
Proof.
intros. ring_simplify. reflexivity.
Qed.
diff --git a/theories/Numbers/Integer/BigZ/ZMake.v b/theories/Numbers/Integer/BigZ/ZMake.v
index 48db793c..0142b36b 100644
--- a/theories/Numbers/Integer/BigZ/ZMake.v
+++ b/theories/Numbers/Integer/BigZ/ZMake.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZMake.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import ZArith.
Require Import BigNumPrelude.
Require Import NSig.
@@ -31,8 +29,11 @@ Module Make (N:NType) <: ZType.
Definition t := t_.
+ Bind Scope abstract_scope with t t_.
+
Definition zero := Pos N.zero.
Definition one := Pos N.one.
+ Definition two := Pos N.two.
Definition minus_one := Neg N.one.
Definition of_Z x :=
@@ -66,6 +67,10 @@ Module Make (N:NType) <: ZType.
exact N.spec_1.
Qed.
+ Theorem spec_2: to_Z two = 2.
+ exact N.spec_2.
+ Qed.
+
Theorem spec_m1: to_Z minus_one = -1.
simpl; rewrite N.spec_1; auto.
Qed.
@@ -104,21 +109,49 @@ Module Make (N:NType) <: ZType.
exfalso. omega.
Qed.
- Definition eq_bool x y :=
+ Definition eqb x y :=
match compare x y with
| Eq => true
| _ => false
end.
- Theorem spec_eq_bool:
- forall x y, eq_bool x y = Zeq_bool (to_Z x) (to_Z y).
+ Theorem spec_eqb x y : eqb x y = Z.eqb (to_Z x) (to_Z y).
Proof.
- unfold eq_bool, Zeq_bool; intros; rewrite spec_compare; reflexivity.
+ apply Bool.eq_iff_eq_true.
+ unfold eqb. rewrite Z.eqb_eq, <- Z.compare_eq_iff, spec_compare.
+ split; [now destruct Z.compare | now intros ->].
Qed.
Definition lt n m := to_Z n < to_Z m.
Definition le n m := to_Z n <= to_Z m.
+
+ Definition ltb (x y : t) : bool :=
+ match compare x y with
+ | Lt => true
+ | _ => false
+ end.
+
+ Theorem spec_ltb x y : ltb x y = Z.ltb (to_Z x) (to_Z y).
+ Proof.
+ apply Bool.eq_iff_eq_true.
+ rewrite Z.ltb_lt. unfold Z.lt, ltb. rewrite spec_compare.
+ split; [now destruct Z.compare | now intros ->].
+ Qed.
+
+ Definition leb (x y : t) : bool :=
+ match compare x y with
+ | Gt => false
+ | _ => true
+ end.
+
+ Theorem spec_leb x y : leb x y = Z.leb (to_Z x) (to_Z y).
+ Proof.
+ apply Bool.eq_iff_eq_true.
+ rewrite Z.leb_le. unfold Z.le, leb. rewrite spec_compare.
+ destruct Z.compare; split; try easy. now destruct 1.
+ Qed.
+
Definition min n m := match compare n m with Gt => m | _ => n end.
Definition max n m := match compare n m with Lt => m | _ => n end.
@@ -273,23 +306,23 @@ Module Make (N:NType) <: ZType.
unfold square, to_Z; intros [x | x]; rewrite N.spec_square; ring.
Qed.
- Definition power_pos x p :=
+ Definition pow_pos x p :=
match x with
- | Pos nx => Pos (N.power_pos nx p)
+ | Pos nx => Pos (N.pow_pos nx p)
| Neg nx =>
match p with
| xH => x
- | xO _ => Pos (N.power_pos nx p)
- | xI _ => Neg (N.power_pos nx p)
+ | xO _ => Pos (N.pow_pos nx p)
+ | xI _ => Neg (N.pow_pos nx p)
end
end.
- Theorem spec_power_pos: forall x n, to_Z (power_pos x n) = to_Z x ^ Zpos n.
+ Theorem spec_pow_pos: forall x n, to_Z (pow_pos x n) = to_Z x ^ Zpos n.
Proof.
assert (F0: forall x, (-x)^2 = x^2).
intros x; rewrite Zpower_2; ring.
- unfold power_pos, to_Z; intros [x | x] [p | p |];
- try rewrite N.spec_power_pos; try ring.
+ unfold pow_pos, to_Z; intros [x | x] [p | p |];
+ try rewrite N.spec_pow_pos; try ring.
assert (F: 0 <= 2 * Zpos p).
assert (0 <= Zpos p); auto with zarith.
rewrite Zpos_xI; repeat rewrite Zpower_exp; auto with zarith.
@@ -302,18 +335,47 @@ Module Make (N:NType) <: ZType.
rewrite F0; ring.
Qed.
- Definition power x n :=
+ Definition pow_N x n :=
match n with
| N0 => one
- | Npos p => power_pos x p
+ | Npos p => pow_pos x p
+ end.
+
+ Theorem spec_pow_N: forall x n, to_Z (pow_N x n) = to_Z x ^ Z_of_N n.
+ Proof.
+ destruct n; simpl. apply N.spec_1.
+ apply spec_pow_pos.
+ Qed.
+
+ Definition pow x y :=
+ match to_Z y with
+ | Z0 => one
+ | Zpos p => pow_pos x p
+ | Zneg p => zero
end.
- Theorem spec_power: forall x n, to_Z (power x n) = to_Z x ^ Z_of_N n.
+ Theorem spec_pow: forall x y, to_Z (pow x y) = to_Z x ^ to_Z y.
Proof.
- destruct n; simpl. rewrite N.spec_1; reflexivity.
- apply spec_power_pos.
+ intros. unfold pow. destruct (to_Z y); simpl.
+ apply N.spec_1.
+ apply spec_pow_pos.
+ apply N.spec_0.
Qed.
+ Definition log2 x :=
+ match x with
+ | Pos nx => Pos (N.log2 nx)
+ | Neg nx => zero
+ end.
+
+ Theorem spec_log2: forall x, to_Z (log2 x) = Z.log2 (to_Z x).
+ Proof.
+ intros. destruct x as [p|p]; simpl. apply N.spec_log2.
+ rewrite N.spec_0.
+ destruct (Z_le_lt_eq_dec _ _ (N.spec_pos p)) as [LT|EQ].
+ rewrite Z.log2_nonpos; auto with zarith.
+ now rewrite <- EQ.
+ Qed.
Definition sqrt x :=
match x with
@@ -321,15 +383,14 @@ Module Make (N:NType) <: ZType.
| Neg nx => Neg N.zero
end.
- Theorem spec_sqrt: forall x, 0 <= to_Z x ->
- to_Z (sqrt x) ^ 2 <= to_Z x < (to_Z (sqrt x) + 1) ^ 2.
+ Theorem spec_sqrt: forall x, to_Z (sqrt x) = Z.sqrt (to_Z x).
Proof.
- unfold to_Z, sqrt; intros [x | x] H.
- exact (N.spec_sqrt x).
- replace (N.to_Z x) with 0.
- rewrite N.spec_0; simpl Zpower; unfold Zpower_pos, iter_pos;
- auto with zarith.
- generalize (N.spec_pos x); auto with zarith.
+ destruct x as [p|p]; simpl.
+ apply N.spec_sqrt.
+ rewrite N.spec_0.
+ destruct (Z_le_lt_eq_dec _ _ (N.spec_pos p)) as [LT|EQ].
+ rewrite Z.sqrt_neg; auto with zarith.
+ now rewrite <- EQ.
Qed.
Definition div_eucl x y :=
@@ -339,12 +400,12 @@ Module Make (N:NType) <: ZType.
(Pos q, Pos r)
| Pos nx, Neg ny =>
let (q, r) := N.div_eucl nx ny in
- if N.eq_bool N.zero r
+ if N.eqb N.zero r
then (Neg q, zero)
else (Neg (N.succ q), Neg (N.sub ny r))
| Neg nx, Pos ny =>
let (q, r) := N.div_eucl nx ny in
- if N.eq_bool N.zero r
+ if N.eqb N.zero r
then (Neg q, zero)
else (Neg (N.succ q), Pos (N.sub ny r))
| Neg nx, Neg ny =>
@@ -368,32 +429,32 @@ Module Make (N:NType) <: ZType.
(* Pos Neg *)
generalize (N.spec_div_eucl x y); destruct (N.div_eucl x y) as (q,r).
break_nonneg x px EQx; break_nonneg y py EQy;
- try (injection 1; intros Hr Hq; rewrite N.spec_eq_bool, N.spec_0, Hr;
+ try (injection 1; intros Hr Hq; rewrite N.spec_eqb, N.spec_0, Hr;
simpl; rewrite Hq, N.spec_0; auto).
change (- Zpos py) with (Zneg py).
assert (GT : Zpos py > 0) by (compute; auto).
generalize (Z_div_mod (Zpos px) (Zpos py) GT).
unfold Zdiv_eucl. destruct (Zdiv_eucl_POS px (Zpos py)) as (q',r').
intros (EQ,MOD). injection 1. intros Hr' Hq'.
- rewrite N.spec_eq_bool, N.spec_0, Hr'.
+ rewrite N.spec_eqb, N.spec_0, Hr'.
break_nonneg r pr EQr.
subst; simpl. rewrite N.spec_0; auto.
- subst. lazy iota beta delta [Zeq_bool Zcompare].
+ subst. lazy iota beta delta [Z.eqb].
rewrite N.spec_sub, N.spec_succ, EQy, EQr. f_equal. omega with *.
(* Neg Pos *)
generalize (N.spec_div_eucl x y); destruct (N.div_eucl x y) as (q,r).
break_nonneg x px EQx; break_nonneg y py EQy;
- try (injection 1; intros Hr Hq; rewrite N.spec_eq_bool, N.spec_0, Hr;
+ try (injection 1; intros Hr Hq; rewrite N.spec_eqb, N.spec_0, Hr;
simpl; rewrite Hq, N.spec_0; auto).
change (- Zpos px) with (Zneg px).
assert (GT : Zpos py > 0) by (compute; auto).
generalize (Z_div_mod (Zpos px) (Zpos py) GT).
unfold Zdiv_eucl. destruct (Zdiv_eucl_POS px (Zpos py)) as (q',r').
intros (EQ,MOD). injection 1. intros Hr' Hq'.
- rewrite N.spec_eq_bool, N.spec_0, Hr'.
+ rewrite N.spec_eqb, N.spec_0, Hr'.
break_nonneg r pr EQr.
subst; simpl. rewrite N.spec_0; auto.
- subst. lazy iota beta delta [Zeq_bool Zcompare].
+ subst. lazy iota beta delta [Z.eqb].
rewrite N.spec_sub, N.spec_succ, EQy, EQr. f_equal. omega with *.
(* Neg Neg *)
generalize (N.spec_div_eucl x y); destruct (N.div_eucl x y) as (q,r).
@@ -422,6 +483,50 @@ Module Make (N:NType) <: ZType.
intros q r q11 r1 H; injection H; auto.
Qed.
+ Definition quot x y :=
+ match x, y with
+ | Pos nx, Pos ny => Pos (N.div nx ny)
+ | Pos nx, Neg ny => Neg (N.div nx ny)
+ | Neg nx, Pos ny => Neg (N.div nx ny)
+ | Neg nx, Neg ny => Pos (N.div nx ny)
+ end.
+
+ Definition rem x y :=
+ if eqb y zero then x
+ else
+ match x, y with
+ | Pos nx, Pos ny => Pos (N.modulo nx ny)
+ | Pos nx, Neg ny => Pos (N.modulo nx ny)
+ | Neg nx, Pos ny => Neg (N.modulo nx ny)
+ | Neg nx, Neg ny => Neg (N.modulo nx ny)
+ end.
+
+ Lemma spec_quot : forall x y, to_Z (quot x y) = (to_Z x) ÷ (to_Z y).
+ Proof.
+ intros [x|x] [y|y]; simpl; symmetry; rewrite N.spec_div;
+ (* Nota: we rely here on [forall a b, a ÷ 0 = b / 0] *)
+ destruct (Z.eq_dec (N.to_Z y) 0) as [EQ|NEQ];
+ try (rewrite EQ; now destruct (N.to_Z x));
+ rewrite ?Z.quot_opp_r, ?Z.quot_opp_l, ?Z.opp_involutive, ?Z.opp_inj_wd;
+ trivial; apply Z.quot_div_nonneg;
+ generalize (N.spec_pos x) (N.spec_pos y); Z.order.
+ Qed.
+
+ Lemma spec_rem : forall x y,
+ to_Z (rem x y) = Z.rem (to_Z x) (to_Z y).
+ Proof.
+ intros x y. unfold rem. rewrite spec_eqb, spec_0.
+ case Z.eqb_spec; intros Hy.
+ (* Nota: we rely here on [Z.rem a 0 = a] *)
+ rewrite Hy. now destruct (to_Z x).
+ destruct x as [x|x], y as [y|y]; simpl in *; symmetry;
+ rewrite ?Z.eq_opp_l, ?Z.opp_0 in Hy;
+ rewrite N.spec_modulo, ?Z.rem_opp_r, ?Z.rem_opp_l, ?Z.opp_involutive,
+ ?Z.opp_inj_wd;
+ trivial; apply Z.rem_mod_nonneg;
+ generalize (N.spec_pos x) (N.spec_pos y); Z.order.
+ Qed.
+
Definition gcd x y :=
match x, y with
| Pos nx, Pos ny => Pos (N.gcd nx ny)
@@ -453,4 +558,204 @@ Module Make (N:NType) <: ZType.
rewrite spec_0, spec_m1. symmetry. rewrite Zsgn_neg; auto with zarith.
Qed.
+ Definition even z :=
+ match z with
+ | Pos n => N.even n
+ | Neg n => N.even n
+ end.
+
+ Definition odd z :=
+ match z with
+ | Pos n => N.odd n
+ | Neg n => N.odd n
+ end.
+
+ Lemma spec_even : forall z, even z = Zeven_bool (to_Z z).
+ Proof.
+ intros [n|n]; simpl; rewrite N.spec_even; trivial.
+ destruct (N.to_Z n) as [|p|p]; now try destruct p.
+ Qed.
+
+ Lemma spec_odd : forall z, odd z = Zodd_bool (to_Z z).
+ Proof.
+ intros [n|n]; simpl; rewrite N.spec_odd; trivial.
+ destruct (N.to_Z n) as [|p|p]; now try destruct p.
+ Qed.
+
+ Definition norm_pos z :=
+ match z with
+ | Pos _ => z
+ | Neg n => if N.eqb n N.zero then Pos n else z
+ end.
+
+ Definition testbit a n :=
+ match norm_pos n, norm_pos a with
+ | Pos p, Pos a => N.testbit a p
+ | Pos p, Neg a => negb (N.testbit (N.pred a) p)
+ | Neg p, _ => false
+ end.
+
+ Definition shiftl a n :=
+ match norm_pos a, n with
+ | Pos a, Pos n => Pos (N.shiftl a n)
+ | Pos a, Neg n => Pos (N.shiftr a n)
+ | Neg a, Pos n => Neg (N.shiftl a n)
+ | Neg a, Neg n => Neg (N.succ (N.shiftr (N.pred a) n))
+ end.
+
+ Definition shiftr a n := shiftl a (opp n).
+
+ Definition lor a b :=
+ match norm_pos a, norm_pos b with
+ | Pos a, Pos b => Pos (N.lor a b)
+ | Neg a, Pos b => Neg (N.succ (N.ldiff (N.pred a) b))
+ | Pos a, Neg b => Neg (N.succ (N.ldiff (N.pred b) a))
+ | Neg a, Neg b => Neg (N.succ (N.land (N.pred a) (N.pred b)))
+ end.
+
+ Definition land a b :=
+ match norm_pos a, norm_pos b with
+ | Pos a, Pos b => Pos (N.land a b)
+ | Neg a, Pos b => Pos (N.ldiff b (N.pred a))
+ | Pos a, Neg b => Pos (N.ldiff a (N.pred b))
+ | Neg a, Neg b => Neg (N.succ (N.lor (N.pred a) (N.pred b)))
+ end.
+
+ Definition ldiff a b :=
+ match norm_pos a, norm_pos b with
+ | Pos a, Pos b => Pos (N.ldiff a b)
+ | Neg a, Pos b => Neg (N.succ (N.lor (N.pred a) b))
+ | Pos a, Neg b => Pos (N.land a (N.pred b))
+ | Neg a, Neg b => Pos (N.ldiff (N.pred b) (N.pred a))
+ end.
+
+ Definition lxor a b :=
+ match norm_pos a, norm_pos b with
+ | Pos a, Pos b => Pos (N.lxor a b)
+ | Neg a, Pos b => Neg (N.succ (N.lxor (N.pred a) b))
+ | Pos a, Neg b => Neg (N.succ (N.lxor a (N.pred b)))
+ | Neg a, Neg b => Pos (N.lxor (N.pred a) (N.pred b))
+ end.
+
+ Definition div2 x := shiftr x one.
+
+ Lemma Zlnot_alt1 : forall x, -(x+1) = Z.lnot x.
+ Proof.
+ unfold Z.lnot, Zpred; auto with zarith.
+ Qed.
+
+ Lemma Zlnot_alt2 : forall x, Z.lnot (x-1) = -x.
+ Proof.
+ unfold Z.lnot, Zpred; auto with zarith.
+ Qed.
+
+ Lemma Zlnot_alt3 : forall x, Z.lnot (-x) = x-1.
+ Proof.
+ unfold Z.lnot, Zpred; auto with zarith.
+ Qed.
+
+ Lemma spec_norm_pos : forall x, to_Z (norm_pos x) = to_Z x.
+ Proof.
+ intros [x|x]; simpl; trivial.
+ rewrite N.spec_eqb, N.spec_0.
+ case Z.eqb_spec; simpl; auto with zarith.
+ Qed.
+
+ Lemma spec_norm_pos_pos : forall x y, norm_pos x = Neg y ->
+ 0 < N.to_Z y.
+ Proof.
+ intros [x|x] y; simpl; try easy.
+ rewrite N.spec_eqb, N.spec_0.
+ case Z.eqb_spec; simpl; try easy.
+ inversion 2. subst. generalize (N.spec_pos y); auto with zarith.
+ Qed.
+
+ Ltac destr_norm_pos x :=
+ rewrite <- (spec_norm_pos x);
+ let H := fresh in
+ let x' := fresh x in
+ assert (H := spec_norm_pos_pos x);
+ destruct (norm_pos x) as [x'|x'];
+ specialize (H x' (eq_refl _)) || clear H.
+
+ Lemma spec_testbit: forall x p, testbit x p = Z.testbit (to_Z x) (to_Z p).
+ Proof.
+ intros x p. unfold testbit.
+ destr_norm_pos p; simpl. destr_norm_pos x; simpl.
+ apply N.spec_testbit.
+ rewrite N.spec_testbit, N.spec_pred, Zmax_r by auto with zarith.
+ symmetry. apply Z.bits_opp. apply N.spec_pos.
+ symmetry. apply Z.testbit_neg_r; auto with zarith.
+ Qed.
+
+ Lemma spec_shiftl: forall x p, to_Z (shiftl x p) = Z.shiftl (to_Z x) (to_Z p).
+ Proof.
+ intros x p. unfold shiftl.
+ destr_norm_pos x; destruct p as [p|p]; simpl;
+ assert (Hp := N.spec_pos p).
+ apply N.spec_shiftl.
+ rewrite Z.shiftl_opp_r. apply N.spec_shiftr.
+ rewrite !N.spec_shiftl.
+ rewrite !Z.shiftl_mul_pow2 by apply N.spec_pos.
+ apply Zopp_mult_distr_l.
+ rewrite Z.shiftl_opp_r, N.spec_succ, N.spec_shiftr, N.spec_pred, Zmax_r
+ by auto with zarith.
+ now rewrite Zlnot_alt1, Z.lnot_shiftr, Zlnot_alt2.
+ Qed.
+
+ Lemma spec_shiftr: forall x p, to_Z (shiftr x p) = Z.shiftr (to_Z x) (to_Z p).
+ Proof.
+ intros. unfold shiftr. rewrite spec_shiftl, spec_opp.
+ apply Z.shiftl_opp_r.
+ Qed.
+
+ Lemma spec_land: forall x y, to_Z (land x y) = Z.land (to_Z x) (to_Z y).
+ Proof.
+ intros x y. unfold land.
+ destr_norm_pos x; destr_norm_pos y; simpl;
+ rewrite ?N.spec_succ, ?N.spec_land, ?N.spec_ldiff, ?N.spec_lor,
+ ?N.spec_pred, ?Zmax_r, ?Zlnot_alt1; auto with zarith.
+ now rewrite Z.ldiff_land, Zlnot_alt2.
+ now rewrite Z.ldiff_land, Z.land_comm, Zlnot_alt2.
+ now rewrite Z.lnot_lor, !Zlnot_alt2.
+ Qed.
+
+ Lemma spec_lor: forall x y, to_Z (lor x y) = Z.lor (to_Z x) (to_Z y).
+ Proof.
+ intros x y. unfold lor.
+ destr_norm_pos x; destr_norm_pos y; simpl;
+ rewrite ?N.spec_succ, ?N.spec_land, ?N.spec_ldiff, ?N.spec_lor,
+ ?N.spec_pred, ?Zmax_r, ?Zlnot_alt1; auto with zarith.
+ now rewrite Z.lnot_ldiff, Z.lor_comm, Zlnot_alt2.
+ now rewrite Z.lnot_ldiff, Zlnot_alt2.
+ now rewrite Z.lnot_land, !Zlnot_alt2.
+ Qed.
+
+ Lemma spec_ldiff: forall x y, to_Z (ldiff x y) = Z.ldiff (to_Z x) (to_Z y).
+ Proof.
+ intros x y. unfold ldiff.
+ destr_norm_pos x; destr_norm_pos y; simpl;
+ rewrite ?N.spec_succ, ?N.spec_land, ?N.spec_ldiff, ?N.spec_lor,
+ ?N.spec_pred, ?Zmax_r, ?Zlnot_alt1; auto with zarith.
+ now rewrite Z.ldiff_land, Zlnot_alt3.
+ now rewrite Z.lnot_lor, Z.ldiff_land, <- Zlnot_alt2.
+ now rewrite 2 Z.ldiff_land, Zlnot_alt2, Z.land_comm, Zlnot_alt3.
+ Qed.
+
+ Lemma spec_lxor: forall x y, to_Z (lxor x y) = Z.lxor (to_Z x) (to_Z y).
+ Proof.
+ intros x y. unfold lxor.
+ destr_norm_pos x; destr_norm_pos y; simpl;
+ rewrite ?N.spec_succ, ?N.spec_lxor, ?N.spec_pred, ?Zmax_r, ?Zlnot_alt1;
+ auto with zarith.
+ now rewrite !Z.lnot_lxor_r, Zlnot_alt2.
+ now rewrite !Z.lnot_lxor_l, Zlnot_alt2.
+ now rewrite <- Z.lxor_lnot_lnot, !Zlnot_alt2.
+ Qed.
+
+ Lemma spec_div2: forall x, to_Z (div2 x) = Z.div2 (to_Z x).
+ Proof.
+ intros x. unfold div2. now rewrite spec_shiftr, Z.div2_spec, spec_1.
+ Qed.
+
End Make.
diff --git a/theories/Numbers/Integer/Binary/ZBinary.v b/theories/Numbers/Integer/Binary/ZBinary.v
index a7e05fee..d7c0abd8 100644
--- a/theories/Numbers/Integer/Binary/ZBinary.v
+++ b/theories/Numbers/Integer/Binary/ZBinary.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,103 +8,31 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZBinary.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Import ZAxioms ZProperties.
-Require Import ZArith_base.
+Require Import ZAxioms ZProperties BinInt.
Local Open Scope Z_scope.
-(** * Implementation of [ZAxiomsSig] by [BinInt.Z] *)
-
-Module ZBinAxiomsMod <: ZAxiomsExtSig.
-
-(** Bi-directional induction. *)
-
-Theorem bi_induction :
- forall A : Z -> Prop, Proper (eq ==> iff) A ->
- A 0 -> (forall n : Z, A n <-> A (Zsucc n)) -> forall n : Z, A n.
-Proof.
-intros A A_wd A0 AS n; apply Zind; clear n.
-assumption.
-intros; rewrite <- Zsucc_succ'. now apply -> AS.
-intros n H. rewrite <- Zpred_pred'. rewrite Zsucc_pred in H. now apply <- AS.
-Qed.
-
-(** Basic operations. *)
-
-Definition eq_equiv : Equivalence (@eq Z) := eq_equivalence.
-Local Obligation Tactic := simpl_relation.
-Program Instance succ_wd : Proper (eq==>eq) Zsucc.
-Program Instance pred_wd : Proper (eq==>eq) Zpred.
-Program Instance add_wd : Proper (eq==>eq==>eq) Zplus.
-Program Instance sub_wd : Proper (eq==>eq==>eq) Zminus.
-Program Instance mul_wd : Proper (eq==>eq==>eq) Zmult.
-
-Definition pred_succ n := eq_sym (Zpred_succ n).
-Definition add_0_l := Zplus_0_l.
-Definition add_succ_l := Zplus_succ_l.
-Definition sub_0_r := Zminus_0_r.
-Definition sub_succ_r := Zminus_succ_r.
-Definition mul_0_l := Zmult_0_l.
-Definition mul_succ_l := Zmult_succ_l.
-
-(** Order *)
-
-Program Instance lt_wd : Proper (eq==>eq==>iff) Zlt.
-
-Definition lt_eq_cases := Zle_lt_or_eq_iff.
-Definition lt_irrefl := Zlt_irrefl.
-Definition lt_succ_r := Zlt_succ_r.
+(** BinInt.Z is already implementing [ZAxiomsMiniSig] *)
-Definition min_l := Zmin_l.
-Definition min_r := Zmin_r.
-Definition max_l := Zmax_l.
-Definition max_r := Zmax_r.
+Module Z
+ <: ZAxiomsSig <: UsualOrderedTypeFull <: TotalOrder
+ <: UsualDecidableTypeFull
+ := BinInt.Z.
-(** Properties specific to integers, not natural numbers. *)
+(** * An [order] tactic for integers *)
-Program Instance opp_wd : Proper (eq==>eq) Zopp.
+Ltac z_order := Z.order.
-Definition succ_pred n := eq_sym (Zsucc_pred n).
-Definition opp_0 := Zopp_0.
-Definition opp_succ := Zopp_succ.
+(** Note that [z_order] is domain-agnostic: it will not prove
+ [1<=2] or [x<=x+x], but rather things like [x<=y -> y<=x -> x=y]. *)
-(** Absolute value and sign *)
-
-Definition abs_eq := Zabs_eq.
-Definition abs_neq := Zabs_non_eq.
-
-Lemma sgn_null : forall x, x = 0 -> Zsgn x = 0.
-Proof. intros. apply <- Zsgn_null; auto. Qed.
-Lemma sgn_pos : forall x, 0 < x -> Zsgn x = 1.
-Proof. intros. apply <- Zsgn_pos; auto. Qed.
-Lemma sgn_neg : forall x, x < 0 -> Zsgn x = -1.
-Proof. intros. apply <- Zsgn_neg; auto. Qed.
-
-(** The instantiation of operations.
- Placing them at the very end avoids having indirections in above lemmas. *)
-
-Definition t := Z.
-Definition eq := (@eq Z).
-Definition zero := 0.
-Definition succ := Zsucc.
-Definition pred := Zpred.
-Definition add := Zplus.
-Definition sub := Zminus.
-Definition mul := Zmult.
-Definition lt := Zlt.
-Definition le := Zle.
-Definition min := Zmin.
-Definition max := Zmax.
-Definition opp := Zopp.
-Definition abs := Zabs.
-Definition sgn := Zsgn.
-
-End ZBinAxiomsMod.
-
-Module Export ZBinPropMod := ZPropFunct ZBinAxiomsMod.
+Section TestOrder.
+ Let test : forall x y, x<=y -> y<=x -> x=y.
+ Proof.
+ z_order.
+ Qed.
+End TestOrder.
(** Z forms a ring *)
@@ -123,18 +51,3 @@ exact Zadd_opp_r.
Qed.
Add Ring ZR : Zring.*)
-
-
-
-(*
-Theorem eq_equiv_e : forall x y : Z, E x y <-> e x y.
-Proof.
-intros x y; unfold E, e, Zeq_bool; split; intro H.
-rewrite H; now rewrite Zcompare_refl.
-rewrite eq_true_unfold_pos in H.
-assert (H1 : (x ?= y) = Eq).
-case_eq (x ?= y); intro H1; rewrite H1 in H; simpl in H;
-[reflexivity | discriminate H | discriminate H].
-now apply Zcompare_Eq_eq.
-Qed.
-*)
diff --git a/theories/Numbers/Integer/NatPairs/ZNatPairs.v b/theories/Numbers/Integer/NatPairs/ZNatPairs.v
index ea3d9ad9..dbcc1961 100644
--- a/theories/Numbers/Integer/NatPairs/ZNatPairs.v
+++ b/theories/Numbers/Integer/NatPairs/ZNatPairs.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,25 +8,25 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZNatPairs.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Import NProperties. (* The most complete file for N *)
-Require Export ZProperties. (* The most complete file for Z *)
+Require Import NSub ZAxioms.
Require Export Ring.
Notation "s #1" := (fst s) (at level 9, format "s '#1'") : pair_scope.
Notation "s #2" := (snd s) (at level 9, format "s '#2'") : pair_scope.
-Open Local Scope pair_scope.
+Local Open Scope pair_scope.
-Module ZPairsAxiomsMod (Import N : NAxiomsSig) <: ZAxiomsSig.
-Module Import NPropMod := NPropFunct N. (* Get all properties of N *)
+Module ZPairsAxiomsMod (Import N : NAxiomsMiniSig) <: ZAxiomsMiniSig.
+ Module Import NProp.
+ Include NSubProp N.
+ End NProp.
Delimit Scope NScope with N.
Bind Scope NScope with N.t.
Infix "==" := N.eq (at level 70) : NScope.
Notation "x ~= y" := (~ N.eq x y) (at level 70) : NScope.
Notation "0" := N.zero : NScope.
-Notation "1" := (N.succ N.zero) : NScope.
+Notation "1" := N.one : NScope.
+Notation "2" := N.two : NScope.
Infix "+" := N.add : NScope.
Infix "-" := N.sub : NScope.
Infix "*" := N.mul : NScope.
@@ -44,6 +44,8 @@ Module Z.
Definition t := (N.t * N.t)%type.
Definition zero : t := (0, 0).
+Definition one : t := (1,0).
+Definition two : t := (2,0).
Definition eq (p q : t) := (p#1 + q#2 == q#1 + p#2).
Definition succ (n : t) : t := (N.succ n#1, n#2).
Definition pred (n : t) : t := (n#1, N.succ n#2).
@@ -74,7 +76,8 @@ Bind Scope ZScope with Z.t.
Infix "==" := Z.eq (at level 70) : ZScope.
Notation "x ~= y" := (~ Z.eq x y) (at level 70) : ZScope.
Notation "0" := Z.zero : ZScope.
-Notation "1" := (Z.succ Z.zero) : ZScope.
+Notation "1" := Z.one : ZScope.
+Notation "2" := Z.two : ZScope.
Infix "+" := Z.add : ZScope.
Infix "-" := Z.sub : ZScope.
Infix "*" := Z.mul : ZScope.
@@ -128,15 +131,14 @@ Qed.
Instance sub_wd : Proper (Z.eq ==> Z.eq ==> Z.eq) Z.sub.
Proof.
-intros n1 m1 H1 n2 m2 H2. rewrite 2 sub_add_opp.
-apply add_wd, opp_wd; auto.
+intros n1 m1 H1 n2 m2 H2. rewrite 2 sub_add_opp. now do 2 f_equiv.
Qed.
Lemma mul_comm : forall n m, n*m == m*n.
Proof.
intros (n1,n2) (m1,m2); compute.
rewrite (add_comm (m1*n2)%N).
-apply N.add_wd; apply N.add_wd; apply mul_comm.
+do 2 f_equiv; apply mul_comm.
Qed.
Instance mul_wd : Proper (Z.eq ==> Z.eq ==> Z.eq) Z.mul.
@@ -160,20 +162,22 @@ Hypothesis A_wd : Proper (Z.eq==>iff) A.
Theorem bi_induction :
A 0 -> (forall n, A n <-> A (Z.succ n)) -> forall n, A n.
Proof.
+Open Scope NScope.
intros A0 AS n; unfold Z.zero, Z.succ, Z.eq in *.
destruct n as [n m].
-cut (forall p, A (p, 0%N)); [intro H1 |].
-cut (forall p, A (0%N, p)); [intro H2 |].
+cut (forall p, A (p, 0)); [intro H1 |].
+cut (forall p, A (0, p)); [intro H2 |].
destruct (add_dichotomy n m) as [[p H] | [p H]].
-rewrite (A_wd (n, m) (0%N, p)) by (rewrite add_0_l; now rewrite add_comm).
+rewrite (A_wd (n, m) (0, p)) by (rewrite add_0_l; now rewrite add_comm).
apply H2.
-rewrite (A_wd (n, m) (p, 0%N)) by now rewrite add_0_r. apply H1.
+rewrite (A_wd (n, m) (p, 0)) by now rewrite add_0_r. apply H1.
induct p. assumption. intros p IH.
-apply -> (A_wd (0%N, p) (1%N, N.succ p)) in IH; [| now rewrite add_0_l, add_1_l].
-now apply <- AS.
+apply (A_wd (0, p) (1, N.succ p)) in IH; [| now rewrite add_0_l, add_1_l].
+rewrite one_succ in IH. now apply AS.
induct p. assumption. intros p IH.
-replace 0%N with (snd (p, 0%N)); [| reflexivity].
-replace (N.succ p) with (N.succ (fst (p, 0%N))); [| reflexivity]. now apply -> AS.
+replace 0 with (snd (p, 0)); [| reflexivity].
+replace (N.succ p) with (N.succ (fst (p, 0))); [| reflexivity]. now apply -> AS.
+Close Scope NScope.
Qed.
End Induction.
@@ -190,6 +194,16 @@ Proof.
intro n; unfold Z.succ, Z.pred, Z.eq; simpl; now nzsimpl.
Qed.
+Theorem one_succ : 1 == Z.succ 0.
+Proof.
+unfold Z.eq; simpl. now nzsimpl'.
+Qed.
+
+Theorem two_succ : 2 == Z.succ 1.
+Proof.
+unfold Z.eq; simpl. now nzsimpl'.
+Qed.
+
Theorem opp_0 : - 0 == 0.
Proof.
unfold Z.opp, Z.eq; simpl. now nzsimpl.
@@ -298,6 +312,8 @@ Qed.
Definition t := Z.t.
Definition eq := Z.eq.
Definition zero := Z.zero.
+Definition one := Z.one.
+Definition two := Z.two.
Definition succ := Z.succ.
Definition pred := Z.pred.
Definition add := Z.add.
diff --git a/theories/Numbers/Integer/SpecViaZ/ZSig.v b/theories/Numbers/Integer/SpecViaZ/ZSig.v
index ff797e32..98ac5dfc 100644
--- a/theories/Numbers/Integer/SpecViaZ/ZSig.v
+++ b/theories/Numbers/Integer/SpecViaZ/ZSig.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,9 +8,7 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: ZSig.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Import ZArith Znumtheory.
+Require Import BinInt.
Open Scope Z_scope.
@@ -35,11 +33,14 @@ Module Type ZType.
Parameter spec_of_Z: forall x, to_Z (of_Z x) = x.
Parameter compare : t -> t -> comparison.
- Parameter eq_bool : t -> t -> bool.
+ Parameter eqb : t -> t -> bool.
+ Parameter ltb : t -> t -> bool.
+ Parameter leb : t -> t -> bool.
Parameter min : t -> t -> t.
Parameter max : t -> t -> t.
Parameter zero : t.
Parameter one : t.
+ Parameter two : t.
Parameter minus_one : t.
Parameter succ : t -> t.
Parameter add : t -> t -> t.
@@ -48,22 +49,39 @@ Module Type ZType.
Parameter opp : t -> t.
Parameter mul : t -> t -> t.
Parameter square : t -> t.
- Parameter power_pos : t -> positive -> t.
- Parameter power : t -> N -> t.
+ Parameter pow_pos : t -> positive -> t.
+ Parameter pow_N : t -> N -> t.
+ Parameter pow : t -> t -> t.
Parameter sqrt : t -> t.
+ Parameter log2 : t -> t.
Parameter div_eucl : t -> t -> t * t.
Parameter div : t -> t -> t.
Parameter modulo : t -> t -> t.
+ Parameter quot : t -> t -> t.
+ Parameter rem : t -> t -> t.
Parameter gcd : t -> t -> t.
Parameter sgn : t -> t.
Parameter abs : t -> t.
+ Parameter even : t -> bool.
+ Parameter odd : t -> bool.
+ Parameter testbit : t -> t -> bool.
+ Parameter shiftr : t -> t -> t.
+ Parameter shiftl : t -> t -> t.
+ Parameter land : t -> t -> t.
+ Parameter lor : t -> t -> t.
+ Parameter ldiff : t -> t -> t.
+ Parameter lxor : t -> t -> t.
+ Parameter div2 : t -> t.
- Parameter spec_compare: forall x y, compare x y = Zcompare [x] [y].
- Parameter spec_eq_bool: forall x y, eq_bool x y = Zeq_bool [x] [y].
- Parameter spec_min : forall x y, [min x y] = Zmin [x] [y].
- Parameter spec_max : forall x y, [max x y] = Zmax [x] [y].
+ Parameter spec_compare: forall x y, compare x y = ([x] ?= [y]).
+ Parameter spec_eqb : forall x y, eqb x y = ([x] =? [y]).
+ Parameter spec_ltb : forall x y, ltb x y = ([x] <? [y]).
+ Parameter spec_leb : forall x y, leb x y = ([x] <=? [y]).
+ Parameter spec_min : forall x y, [min x y] = Z.min [x] [y].
+ Parameter spec_max : forall x y, [max x y] = Z.max [x] [y].
Parameter spec_0: [zero] = 0.
Parameter spec_1: [one] = 1.
+ Parameter spec_2: [two] = 2.
Parameter spec_m1: [minus_one] = -1.
Parameter spec_succ: forall n, [succ n] = [n] + 1.
Parameter spec_add: forall x y, [add x y] = [x] + [y].
@@ -72,17 +90,30 @@ Module Type ZType.
Parameter spec_opp: forall x, [opp x] = - [x].
Parameter spec_mul: forall x y, [mul x y] = [x] * [y].
Parameter spec_square: forall x, [square x] = [x] * [x].
- Parameter spec_power_pos: forall x n, [power_pos x n] = [x] ^ Zpos n.
- Parameter spec_power: forall x n, [power x n] = [x] ^ Z_of_N n.
- Parameter spec_sqrt: forall x, 0 <= [x] ->
- [sqrt x] ^ 2 <= [x] < ([sqrt x] + 1) ^ 2.
+ Parameter spec_pow_pos: forall x n, [pow_pos x n] = [x] ^ Zpos n.
+ Parameter spec_pow_N: forall x n, [pow_N x n] = [x] ^ Z.of_N n.
+ Parameter spec_pow: forall x n, [pow x n] = [x] ^ [n].
+ Parameter spec_sqrt: forall x, [sqrt x] = Z.sqrt [x].
+ Parameter spec_log2: forall x, [log2 x] = Z.log2 [x].
Parameter spec_div_eucl: forall x y,
- let (q,r) := div_eucl x y in ([q], [r]) = Zdiv_eucl [x] [y].
+ let (q,r) := div_eucl x y in ([q], [r]) = Z.div_eucl [x] [y].
Parameter spec_div: forall x y, [div x y] = [x] / [y].
Parameter spec_modulo: forall x y, [modulo x y] = [x] mod [y].
- Parameter spec_gcd: forall a b, [gcd a b] = Zgcd (to_Z a) (to_Z b).
- Parameter spec_sgn : forall x, [sgn x] = Zsgn [x].
- Parameter spec_abs : forall x, [abs x] = Zabs [x].
+ Parameter spec_quot: forall x y, [quot x y] = [x] ÷ [y].
+ Parameter spec_rem: forall x y, [rem x y] = Z.rem [x] [y].
+ Parameter spec_gcd: forall a b, [gcd a b] = Z.gcd [a] [b].
+ Parameter spec_sgn : forall x, [sgn x] = Z.sgn [x].
+ Parameter spec_abs : forall x, [abs x] = Z.abs [x].
+ Parameter spec_even : forall x, even x = Z.even [x].
+ Parameter spec_odd : forall x, odd x = Z.odd [x].
+ Parameter spec_testbit: forall x p, testbit x p = Z.testbit [x] [p].
+ Parameter spec_shiftr: forall x p, [shiftr x p] = Z.shiftr [x] [p].
+ Parameter spec_shiftl: forall x p, [shiftl x p] = Z.shiftl [x] [p].
+ Parameter spec_land: forall x y, [land x y] = Z.land [x] [y].
+ Parameter spec_lor: forall x y, [lor x y] = Z.lor [x] [y].
+ Parameter spec_ldiff: forall x y, [ldiff x y] = Z.ldiff [x] [y].
+ Parameter spec_lxor: forall x y, [lxor x y] = Z.lxor [x] [y].
+ Parameter spec_div2: forall x, [div2 x] = Z.div2 [x].
End ZType.
@@ -90,12 +121,15 @@ Module Type ZType_Notation (Import Z:ZType).
Notation "[ x ]" := (to_Z x).
Infix "==" := eq (at level 70).
Notation "0" := zero.
+ Notation "1" := one.
+ Notation "2" := two.
Infix "+" := add.
Infix "-" := sub.
Infix "*" := mul.
+ Infix "^" := pow.
Notation "- x" := (opp x).
Infix "<=" := le.
Infix "<" := lt.
End ZType_Notation.
-Module Type ZType' := ZType <+ ZType_Notation. \ No newline at end of file
+Module Type ZType' := ZType <+ ZType_Notation.
diff --git a/theories/Numbers/Integer/SpecViaZ/ZSigZAxioms.v b/theories/Numbers/Integer/SpecViaZ/ZSigZAxioms.v
index 879a17dd..bfbc063c 100644
--- a/theories/Numbers/Integer/SpecViaZ/ZSigZAxioms.v
+++ b/theories/Numbers/Integer/SpecViaZ/ZSigZAxioms.v
@@ -1,27 +1,24 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: ZSigZAxioms.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
+Require Import Bool ZArith OrdersFacts Nnat ZAxioms ZSig.
-Require Import ZArith ZAxioms ZDivFloor ZSig.
+(** * The interface [ZSig.ZType] implies the interface [ZAxiomsSig] *)
-(** * The interface [ZSig.ZType] implies the interface [ZAxiomsSig]
-
- It also provides [sgn], [abs], [div], [mod]
-*)
-
-
-Module ZTypeIsZAxioms (Import Z : ZType').
+Module ZTypeIsZAxioms (Import ZZ : ZType').
Hint Rewrite
- spec_0 spec_1 spec_add spec_sub spec_pred spec_succ
- spec_mul spec_opp spec_of_Z spec_div spec_modulo
- spec_compare spec_eq_bool spec_max spec_min spec_abs spec_sgn
+ spec_0 spec_1 spec_2 spec_add spec_sub spec_pred spec_succ
+ spec_mul spec_opp spec_of_Z spec_div spec_modulo spec_square spec_sqrt
+ spec_compare spec_eqb spec_ltb spec_leb spec_max spec_min
+ spec_abs spec_sgn spec_pow spec_log2 spec_even spec_odd spec_gcd
+ spec_quot spec_rem spec_testbit spec_shiftl spec_shiftr
+ spec_land spec_lor spec_ldiff spec_lxor spec_div2
: zsimpl.
Ltac zsimpl := autorewrite with zsimpl.
@@ -44,9 +41,19 @@ Proof.
intros. zify. auto with zarith.
Qed.
+Theorem one_succ : 1 == succ 0.
+Proof.
+now zify.
+Qed.
+
+Theorem two_succ : 2 == succ 1.
+Proof.
+now zify.
+Qed.
+
Section Induction.
-Variable A : Z.t -> Prop.
+Variable A : ZZ.t -> Prop.
Hypothesis A_wd : Proper (eq==>iff) A.
Hypothesis A0 : A 0.
Hypothesis AS : forall n, A n <-> A (succ n).
@@ -131,36 +138,66 @@ Qed.
(** Order *)
-Lemma compare_spec : forall x y, CompSpec eq lt x y (compare x y).
+Lemma eqb_eq x y : eqb x y = true <-> x == y.
+Proof.
+ zify. apply Z.eqb_eq.
+Qed.
+
+Lemma leb_le x y : leb x y = true <-> x <= y.
+Proof.
+ zify. apply Z.leb_le.
+Qed.
+
+Lemma ltb_lt x y : ltb x y = true <-> x < y.
Proof.
- intros. zify. destruct (Zcompare_spec [x] [y]); auto.
+ zify. apply Z.ltb_lt.
Qed.
-Definition eqb := eq_bool.
+Lemma compare_eq_iff n m : compare n m = Eq <-> n == m.
+Proof.
+ intros. zify. apply Z.compare_eq_iff.
+Qed.
+
+Lemma compare_lt_iff n m : compare n m = Lt <-> n < m.
+Proof.
+ intros. zify. reflexivity.
+Qed.
-Lemma eqb_eq : forall x y, eq_bool x y = true <-> x == y.
+Lemma compare_le_iff n m : compare n m <> Gt <-> n <= m.
Proof.
- intros. zify. symmetry. apply Zeq_is_eq_bool.
+ intros. zify. reflexivity.
Qed.
+Lemma compare_antisym n m : compare m n = CompOpp (compare n m).
+Proof.
+ intros. zify. apply Z.compare_antisym.
+Qed.
+
+Include BoolOrderFacts ZZ ZZ ZZ [no inline].
+
Instance compare_wd : Proper (eq ==> eq ==> Logic.eq) compare.
Proof.
-intros x x' Hx y y' Hy. rewrite 2 spec_compare, Hx, Hy; intuition.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Instance lt_wd : Proper (eq ==> eq ==> iff) lt.
+Instance eqb_wd : Proper (eq ==> eq ==> Logic.eq) eqb.
Proof.
-intros x x' Hx y y' Hy; unfold lt; rewrite Hx, Hy; intuition.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Theorem lt_eq_cases : forall n m, n <= m <-> n < m \/ n == m.
+Instance ltb_wd : Proper (eq ==> eq ==> Logic.eq) ltb.
Proof.
-intros. zify. omega.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Theorem lt_irrefl : forall n, ~ n < n.
+Instance leb_wd : Proper (eq ==> eq ==> Logic.eq) leb.
Proof.
-intros. zify. omega.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
+Qed.
+
+Instance lt_wd : Proper (eq ==> eq ==> iff) lt.
+Proof.
+intros x x' Hx y y' Hy; unfold lt; rewrite Hx, Hy; intuition.
Qed.
Theorem lt_succ_r : forall n m, n < (succ m) <-> n <= m.
@@ -190,13 +227,15 @@ Qed.
(** Part specific to integers, not natural numbers *)
-Program Instance opp_wd : Proper (eq ==> eq) opp.
-
Theorem succ_pred : forall n, succ (pred n) == n.
Proof.
intros. zify. auto with zarith.
Qed.
+(** Opp *)
+
+Program Instance opp_wd : Proper (eq ==> eq) opp.
+
Theorem opp_0 : - 0 == 0.
Proof.
intros. zify. auto with zarith.
@@ -207,6 +246,8 @@ Proof.
intros. zify. auto with zarith.
Qed.
+(** Abs / Sgn *)
+
Theorem abs_eq : forall n, 0 <= n -> abs n == n.
Proof.
intros n. zify. omega with *.
@@ -222,16 +263,102 @@ Proof.
intros n. zify. omega with *.
Qed.
-Theorem sgn_pos : forall n, 0<n -> sgn n == succ 0.
+Theorem sgn_pos : forall n, 0<n -> sgn n == 1.
Proof.
intros n. zify. omega with *.
Qed.
-Theorem sgn_neg : forall n, n<0 -> sgn n == opp (succ 0).
+Theorem sgn_neg : forall n, n<0 -> sgn n == opp 1.
Proof.
intros n. zify. omega with *.
Qed.
+(** Power *)
+
+Program Instance pow_wd : Proper (eq==>eq==>eq) pow.
+
+Lemma pow_0_r : forall a, a^0 == 1.
+Proof.
+ intros. now zify.
+Qed.
+
+Lemma pow_succ_r : forall a b, 0<=b -> a^(succ b) == a * a^b.
+Proof.
+ intros a b. zify. intros. now rewrite Z.add_1_r, Z.pow_succ_r.
+Qed.
+
+Lemma pow_neg_r : forall a b, b<0 -> a^b == 0.
+Proof.
+ intros a b. zify. intros Hb.
+ destruct [b]; reflexivity || discriminate.
+Qed.
+
+Lemma pow_pow_N : forall a b, 0<=b -> a^b == pow_N a (Z.to_N (to_Z b)).
+Proof.
+ intros a b. zify. intros Hb. now rewrite spec_pow_N, Z2N.id.
+Qed.
+
+Lemma pow_pos_N : forall a p, pow_pos a p == pow_N a (Npos p).
+Proof.
+ intros a b. red. now rewrite spec_pow_N, spec_pow_pos.
+Qed.
+
+(** Square *)
+
+Lemma square_spec n : square n == n * n.
+Proof.
+ now zify.
+Qed.
+
+(** Sqrt *)
+
+Lemma sqrt_spec : forall n, 0<=n ->
+ (sqrt n)*(sqrt n) <= n /\ n < (succ (sqrt n))*(succ (sqrt n)).
+Proof.
+ intros n. zify. apply Z.sqrt_spec.
+Qed.
+
+Lemma sqrt_neg : forall n, n<0 -> sqrt n == 0.
+Proof.
+ intros n. zify. apply Z.sqrt_neg.
+Qed.
+
+(** Log2 *)
+
+Lemma log2_spec : forall n, 0<n ->
+ 2^(log2 n) <= n /\ n < 2^(succ (log2 n)).
+Proof.
+ intros n. zify. apply Z.log2_spec.
+Qed.
+
+Lemma log2_nonpos : forall n, n<=0 -> log2 n == 0.
+Proof.
+ intros n. zify. apply Z.log2_nonpos.
+Qed.
+
+(** Even / Odd *)
+
+Definition Even n := exists m, n == 2*m.
+Definition Odd n := exists m, n == 2*m+1.
+
+Lemma even_spec n : even n = true <-> Even n.
+Proof.
+ unfold Even. zify. rewrite Z.even_spec.
+ split; intros (m,Hm).
+ - exists (of_Z m). now zify.
+ - exists [m]. revert Hm. now zify.
+Qed.
+
+Lemma odd_spec n : odd n = true <-> Odd n.
+Proof.
+ unfold Odd. zify. rewrite Z.odd_spec.
+ split; intros (m,Hm).
+ - exists (of_Z m). now zify.
+ - exists [m]. revert Hm. now zify.
+Qed.
+
+(** Div / Mod *)
+
Program Instance div_wd : Proper (eq==>eq==>eq) div.
Program Instance mod_wd : Proper (eq==>eq==>eq) modulo.
@@ -252,8 +379,149 @@ Proof.
intros a b. zify. intros. apply Z_mod_neg; auto with zarith.
Qed.
+Definition mod_bound_pos :
+ forall a b, 0<=a -> 0<b -> 0 <= modulo a b /\ modulo a b < b :=
+ fun a b _ H => mod_pos_bound a b H.
+
+(** Quot / Rem *)
+
+Program Instance quot_wd : Proper (eq==>eq==>eq) quot.
+Program Instance rem_wd : Proper (eq==>eq==>eq) rem.
+
+Theorem quot_rem : forall a b, ~b==0 -> a == b*(quot a b) + rem a b.
+Proof.
+intros a b. zify. apply Z.quot_rem.
+Qed.
+
+Theorem rem_bound_pos :
+ forall a b, 0<=a -> 0<b -> 0 <= rem a b /\ rem a b < b.
+Proof.
+intros a b. zify. apply Z.rem_bound_pos.
+Qed.
+
+Theorem rem_opp_l : forall a b, ~b==0 -> rem (-a) b == -(rem a b).
+Proof.
+intros a b. zify. apply Z.rem_opp_l.
+Qed.
+
+Theorem rem_opp_r : forall a b, ~b==0 -> rem a (-b) == rem a b.
+Proof.
+intros a b. zify. apply Z.rem_opp_r.
+Qed.
+
+(** Gcd *)
+
+Definition divide n m := exists p, m == p*n.
+Local Notation "( x | y )" := (divide x y) (at level 0).
+
+Lemma spec_divide : forall n m, (n|m) <-> Z.divide [n] [m].
+Proof.
+ intros n m. split.
+ - intros (p,H). exists [p]. revert H; now zify.
+ - intros (z,H). exists (of_Z z). now zify.
+Qed.
+
+Lemma gcd_divide_l : forall n m, (gcd n m | n).
+Proof.
+ intros n m. apply spec_divide. zify. apply Z.gcd_divide_l.
+Qed.
+
+Lemma gcd_divide_r : forall n m, (gcd n m | m).
+Proof.
+ intros n m. apply spec_divide. zify. apply Z.gcd_divide_r.
+Qed.
+
+Lemma gcd_greatest : forall n m p, (p|n) -> (p|m) -> (p|gcd n m).
+Proof.
+ intros n m p. rewrite !spec_divide. zify. apply Z.gcd_greatest.
+Qed.
+
+Lemma gcd_nonneg : forall n m, 0 <= gcd n m.
+Proof.
+ intros. zify. apply Z.gcd_nonneg.
+Qed.
+
+(** Bitwise operations *)
+
+Program Instance testbit_wd : Proper (eq==>eq==>Logic.eq) testbit.
+
+Lemma testbit_odd_0 : forall a, testbit (2*a+1) 0 = true.
+Proof.
+ intros. zify. apply Z.testbit_odd_0.
+Qed.
+
+Lemma testbit_even_0 : forall a, testbit (2*a) 0 = false.
+Proof.
+ intros. zify. apply Z.testbit_even_0.
+Qed.
+
+Lemma testbit_odd_succ : forall a n, 0<=n ->
+ testbit (2*a+1) (succ n) = testbit a n.
+Proof.
+ intros a n. zify. apply Z.testbit_odd_succ.
+Qed.
+
+Lemma testbit_even_succ : forall a n, 0<=n ->
+ testbit (2*a) (succ n) = testbit a n.
+Proof.
+ intros a n. zify. apply Z.testbit_even_succ.
+Qed.
+
+Lemma testbit_neg_r : forall a n, n<0 -> testbit a n = false.
+Proof.
+ intros a n. zify. apply Z.testbit_neg_r.
+Qed.
+
+Lemma shiftr_spec : forall a n m, 0<=m ->
+ testbit (shiftr a n) m = testbit a (m+n).
+Proof.
+ intros a n m. zify. apply Z.shiftr_spec.
+Qed.
+
+Lemma shiftl_spec_high : forall a n m, 0<=m -> n<=m ->
+ testbit (shiftl a n) m = testbit a (m-n).
+Proof.
+ intros a n m. zify. intros Hn H.
+ now apply Z.shiftl_spec_high.
+Qed.
+
+Lemma shiftl_spec_low : forall a n m, m<n ->
+ testbit (shiftl a n) m = false.
+Proof.
+ intros a n m. zify. intros H. now apply Z.shiftl_spec_low.
+Qed.
+
+Lemma land_spec : forall a b n,
+ testbit (land a b) n = testbit a n && testbit b n.
+Proof.
+ intros a n m. zify. now apply Z.land_spec.
+Qed.
+
+Lemma lor_spec : forall a b n,
+ testbit (lor a b) n = testbit a n || testbit b n.
+Proof.
+ intros a n m. zify. now apply Z.lor_spec.
+Qed.
+
+Lemma ldiff_spec : forall a b n,
+ testbit (ldiff a b) n = testbit a n && negb (testbit b n).
+Proof.
+ intros a n m. zify. now apply Z.ldiff_spec.
+Qed.
+
+Lemma lxor_spec : forall a b n,
+ testbit (lxor a b) n = xorb (testbit a n) (testbit b n).
+Proof.
+ intros a n m. zify. now apply Z.lxor_spec.
+Qed.
+
+Lemma div2_spec : forall a, div2 a == shiftr a 1.
+Proof.
+ intros a. zify. now apply Z.div2_spec.
+Qed.
+
End ZTypeIsZAxioms.
-Module ZType_ZAxioms (Z : ZType)
- <: ZAxiomsSig <: ZDivSig <: HasCompare Z <: HasEqBool Z <: HasMinMax Z
- := Z <+ ZTypeIsZAxioms.
+Module ZType_ZAxioms (ZZ : ZType)
+ <: ZAxiomsSig <: OrderFunctions ZZ <: HasMinMax ZZ
+ := ZZ <+ ZTypeIsZAxioms.
diff --git a/theories/Numbers/NaryFunctions.v b/theories/Numbers/NaryFunctions.v
index 1d9a65dc..c1b7bafa 100644
--- a/theories/Numbers/NaryFunctions.v
+++ b/theories/Numbers/NaryFunctions.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(* Pierre Letouzey, Jerome Vouillon, PPS, Paris 7, 2008 *)
(************************************************************************)
-(*i $Id: NaryFunctions.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Local Open Scope type_scope.
Require Import List.
diff --git a/theories/Numbers/NatInt/NZAdd.v b/theories/Numbers/NatInt/NZAdd.v
index 782619f0..8bed3027 100644
--- a/theories/Numbers/NatInt/NZAdd.v
+++ b/theories/Numbers/NatInt/NZAdd.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,16 +8,15 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZAdd.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NZAxioms NZBase.
-Module Type NZAddPropSig
- (Import NZ : NZAxiomsSig')(Import NZBase : NZBasePropSig NZ).
+Module Type NZAddProp (Import NZ : NZAxiomsSig')(Import NZBase : NZBaseProp NZ).
Hint Rewrite
pred_succ add_0_l add_succ_l mul_0_l mul_succ_l sub_0_r sub_succ_r : nz.
+Hint Rewrite one_succ two_succ : nz'.
Ltac nzsimpl := autorewrite with nz.
+Ltac nzsimpl' := autorewrite with nz nz'.
Theorem add_0_r : forall n, n + 0 == n.
Proof.
@@ -31,6 +30,11 @@ intros n m; nzinduct n. now nzsimpl.
intro. nzsimpl. now rewrite succ_inj_wd.
Qed.
+Theorem add_succ_comm : forall n m, S n + m == n + S m.
+Proof.
+intros n m. now rewrite add_succ_r, add_succ_l.
+Qed.
+
Hint Rewrite add_0_r add_succ_r : nz.
Theorem add_comm : forall n m, n + m == m + n.
@@ -41,14 +45,16 @@ Qed.
Theorem add_1_l : forall n, 1 + n == S n.
Proof.
-intro n; now nzsimpl.
+intro n; now nzsimpl'.
Qed.
Theorem add_1_r : forall n, n + 1 == S n.
Proof.
-intro n; now nzsimpl.
+intro n; now nzsimpl'.
Qed.
+Hint Rewrite add_1_l add_1_r : nz.
+
Theorem add_assoc : forall n m p, n + (m + p) == (n + m) + p.
Proof.
intros n m p; nzinduct n. now nzsimpl.
@@ -78,13 +84,19 @@ Qed.
Theorem add_shuffle2 : forall n m p q, (n + m) + (p + q) == (n + q) + (m + p).
Proof.
-intros n m p q.
-rewrite 2 add_assoc, add_shuffle0, add_cancel_r. apply add_shuffle0.
+intros n m p q. rewrite (add_comm p). apply add_shuffle1.
+Qed.
+
+Theorem add_shuffle3 : forall n m p, n + (m + p) == m + (n + p).
+Proof.
+intros n m p. now rewrite add_comm, <- add_assoc, (add_comm p).
Qed.
Theorem sub_1_r : forall n, n - 1 == P n.
Proof.
-intro n; now nzsimpl.
+intro n; now nzsimpl'.
Qed.
-End NZAddPropSig.
+Hint Rewrite sub_1_r : nz.
+
+End NZAddProp.
diff --git a/theories/Numbers/NatInt/NZAddOrder.v b/theories/Numbers/NatInt/NZAddOrder.v
index ed56cd8f..ee03e5f9 100644
--- a/theories/Numbers/NatInt/NZAddOrder.v
+++ b/theories/Numbers/NatInt/NZAddOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZAddOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NZAxioms NZBase NZMul NZOrder.
-Module Type NZAddOrderPropSig (Import NZ : NZOrdAxiomsSig').
-Include NZBasePropSig NZ <+ NZMulPropSig NZ <+ NZOrderPropSig NZ.
+Module Type NZAddOrderProp (Import NZ : NZOrdAxiomsSig').
+Include NZBaseProp NZ <+ NZMulProp NZ <+ NZOrderProp NZ.
Theorem add_lt_mono_l : forall n m p, n < m <-> p + n < p + m.
Proof.
@@ -30,7 +28,7 @@ Theorem add_lt_mono : forall n m p q, n < m -> p < q -> n + p < m + q.
Proof.
intros n m p q H1 H2.
apply lt_trans with (m + p);
-[now apply -> add_lt_mono_r | now apply -> add_lt_mono_l].
+[now apply add_lt_mono_r | now apply add_lt_mono_l].
Qed.
Theorem add_le_mono_l : forall n m p, n <= m <-> p + n <= p + m.
@@ -48,21 +46,21 @@ Theorem add_le_mono : forall n m p q, n <= m -> p <= q -> n + p <= m + q.
Proof.
intros n m p q H1 H2.
apply le_trans with (m + p);
-[now apply -> add_le_mono_r | now apply -> add_le_mono_l].
+[now apply add_le_mono_r | now apply add_le_mono_l].
Qed.
Theorem add_lt_le_mono : forall n m p q, n < m -> p <= q -> n + p < m + q.
Proof.
intros n m p q H1 H2.
apply lt_le_trans with (m + p);
-[now apply -> add_lt_mono_r | now apply -> add_le_mono_l].
+[now apply add_lt_mono_r | now apply add_le_mono_l].
Qed.
Theorem add_le_lt_mono : forall n m p q, n <= m -> p < q -> n + p < m + q.
Proof.
intros n m p q H1 H2.
apply le_lt_trans with (m + p);
-[now apply -> add_le_mono_r | now apply -> add_lt_mono_l].
+[now apply add_le_mono_r | now apply add_lt_mono_l].
Qed.
Theorem add_pos_pos : forall n m, 0 < n -> 0 < m -> 0 < n + m.
@@ -149,5 +147,22 @@ Proof.
intros n m H; apply add_le_cases; now nzsimpl.
Qed.
-End NZAddOrderPropSig.
+(** Substraction *)
+
+(** We can prove the existence of a subtraction of any number by
+ a smaller one *)
+
+Lemma le_exists_sub : forall n m, n<=m -> exists p, m == p+n /\ 0<=p.
+Proof.
+ intros n m H. apply le_ind with (4:=H). solve_proper.
+ exists 0; nzsimpl; split; order.
+ clear m H. intros m H (p & EQ & LE). exists (S p).
+ split. nzsimpl. now f_equiv. now apply le_le_succ_r.
+Qed.
+
+(** For the moment, it doesn't seem possible to relate
+ this existing subtraction with [sub].
+*)
+
+End NZAddOrderProp.
diff --git a/theories/Numbers/NatInt/NZAxioms.v b/theories/Numbers/NatInt/NZAxioms.v
index 33236cde..fcd98787 100644
--- a/theories/Numbers/NatInt/NZAxioms.v
+++ b/theories/Numbers/NatInt/NZAxioms.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,8 +8,6 @@
(** Initial Author : Evgeny Makarov, INRIA, 2007 *)
-(*i $Id: NZAxioms.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export Equalities Orders NumPrelude GenericMinMax.
(** Axiomatization of a domain with zero, successor, predecessor,
@@ -20,7 +18,7 @@ Require Export Equalities Orders NumPrelude GenericMinMax.
*)
Module Type ZeroSuccPred (Import T:Typ).
- Parameter Inline zero : t.
+ Parameter Inline(20) zero : t.
Parameters Inline succ pred : t -> t.
End ZeroSuccPred.
@@ -28,8 +26,6 @@ Module Type ZeroSuccPredNotation (T:Typ)(Import NZ:ZeroSuccPred T).
Notation "0" := zero.
Notation S := succ.
Notation P := pred.
- Notation "1" := (S 0).
- Notation "2" := (S 1).
End ZeroSuccPredNotation.
Module Type ZeroSuccPred' (T:Typ) :=
@@ -44,9 +40,33 @@ Module Type IsNZDomain (Import E:Eq')(Import NZ:ZeroSuccPred' E).
A 0 -> (forall n, A n <-> A (S n)) -> forall n, A n.
End IsNZDomain.
-Module Type NZDomainSig := EqualityType <+ ZeroSuccPred <+ IsNZDomain.
-Module Type NZDomainSig' := EqualityType' <+ ZeroSuccPred' <+ IsNZDomain.
+(** Axiomatization of some more constants
+
+ Simply denoting "1" for (S 0) and so on works ok when implementing
+ by nat, but leaves some (Nsucc N0) when implementing by N.
+*)
+
+Module Type OneTwo (Import T:Typ).
+ Parameter Inline(20) one two : t.
+End OneTwo.
+Module Type OneTwoNotation (T:Typ)(Import NZ:OneTwo T).
+ Notation "1" := one.
+ Notation "2" := two.
+End OneTwoNotation.
+
+Module Type OneTwo' (T:Typ) := OneTwo T <+ OneTwoNotation T.
+
+Module Type IsOneTwo (E:Eq')(Z:ZeroSuccPred' E)(O:OneTwo' E).
+ Import E Z O.
+ Axiom one_succ : 1 == S 0.
+ Axiom two_succ : 2 == S 1.
+End IsOneTwo.
+
+Module Type NZDomainSig :=
+ EqualityType <+ ZeroSuccPred <+ IsNZDomain <+ OneTwo <+ IsOneTwo.
+Module Type NZDomainSig' :=
+ EqualityType' <+ ZeroSuccPred' <+ IsNZDomain <+ OneTwo' <+ IsOneTwo.
(** Axiomatization of basic operations : [+] [-] [*] *)
@@ -117,3 +137,9 @@ Module Type NZDecOrdSig' := NZOrdSig' <+ HasCompare.
Module Type NZDecOrdAxiomsSig := NZOrdAxiomsSig <+ HasCompare.
Module Type NZDecOrdAxiomsSig' := NZOrdAxiomsSig' <+ HasCompare.
+(** A square function *)
+
+Module Type NZSquare (Import NZ : NZBasicFunsSig').
+ Parameter Inline square : t -> t.
+ Axiom square_spec : forall n, square n == n * n.
+End NZSquare.
diff --git a/theories/Numbers/NatInt/NZBase.v b/theories/Numbers/NatInt/NZBase.v
index 119f8265..65b64635 100644
--- a/theories/Numbers/NatInt/NZBase.v
+++ b/theories/Numbers/NatInt/NZBase.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,11 +8,14 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZBase.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NZAxioms.
-Module Type NZBasePropSig (Import NZ : NZDomainSig').
+Module Type NZBaseProp (Import NZ : NZDomainSig').
+
+(** An artificial scope meant to be substituted later *)
+
+Delimit Scope abstract_scope with abstract.
+Bind Scope abstract_scope with t.
Include BackportEq NZ NZ. (** eq_refl, eq_sym, eq_trans *)
@@ -50,7 +53,7 @@ Theorem succ_inj_wd : forall n1 n2, S n1 == S n2 <-> n1 == n2.
Proof.
intros; split.
apply succ_inj.
-apply succ_wd.
+intros. now f_equiv.
Qed.
Theorem succ_inj_wd_neg : forall n m, S n ~= S m <-> n ~= m.
@@ -63,7 +66,7 @@ left-inverse to the successor at this point *)
Section CentralInduction.
-Variable A : predicate t.
+Variable A : t -> Prop.
Hypothesis A_wd : Proper (eq==>iff) A.
Theorem central_induction :
@@ -72,7 +75,7 @@ Theorem central_induction :
forall n, A n.
Proof.
intros z Base Step; revert Base; pattern z; apply bi_induction.
-solve_predicate_wd.
+solve_proper.
intro; now apply bi_induction.
intro; pose proof (Step n); tauto.
Qed.
@@ -85,5 +88,5 @@ Tactic Notation "nzinduct" ident(n) :=
Tactic Notation "nzinduct" ident(n) constr(u) :=
induction_maker n ltac:(apply central_induction with (z := u)).
-End NZBasePropSig.
+End NZBaseProp.
diff --git a/theories/Numbers/NatInt/NZBits.v b/theories/Numbers/NatInt/NZBits.v
new file mode 100644
index 00000000..dc97eeb1
--- /dev/null
+++ b/theories/Numbers/NatInt/NZBits.v
@@ -0,0 +1,64 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import Bool NZAxioms NZMulOrder NZParity NZPow NZDiv NZLog.
+
+(** Axiomatization of some bitwise operations *)
+
+Module Type Bits (Import A : Typ).
+ Parameter Inline testbit : t -> t -> bool.
+ Parameters Inline shiftl shiftr land lor ldiff lxor : t -> t -> t.
+ Parameter Inline div2 : t -> t.
+End Bits.
+
+Module Type BitsNotation (Import A : Typ)(Import B : Bits A).
+ Notation "a .[ n ]" := (testbit a n) (at level 5, format "a .[ n ]").
+ Infix ">>" := shiftr (at level 30, no associativity).
+ Infix "<<" := shiftl (at level 30, no associativity).
+End BitsNotation.
+
+Module Type Bits' (A:Typ) := Bits A <+ BitsNotation A.
+
+Module Type NZBitsSpec
+ (Import A : NZOrdAxiomsSig')(Import B : Bits' A).
+
+ Declare Instance testbit_wd : Proper (eq==>eq==>Logic.eq) testbit.
+ Axiom testbit_odd_0 : forall a, (2*a+1).[0] = true.
+ Axiom testbit_even_0 : forall a, (2*a).[0] = false.
+ Axiom testbit_odd_succ : forall a n, 0<=n -> (2*a+1).[S n] = a.[n].
+ Axiom testbit_even_succ : forall a n, 0<=n -> (2*a).[S n] = a.[n].
+ Axiom testbit_neg_r : forall a n, n<0 -> a.[n] = false.
+
+ Axiom shiftr_spec : forall a n m, 0<=m -> (a >> n).[m] = a.[m+n].
+ Axiom shiftl_spec_high : forall a n m, 0<=m -> n<=m -> (a << n).[m] = a.[m-n].
+ Axiom shiftl_spec_low : forall a n m, m<n -> (a << n).[m] = false.
+
+ Axiom land_spec : forall a b n, (land a b).[n] = a.[n] && b.[n].
+ Axiom lor_spec : forall a b n, (lor a b).[n] = a.[n] || b.[n].
+ Axiom ldiff_spec : forall a b n, (ldiff a b).[n] = a.[n] && negb b.[n].
+ Axiom lxor_spec : forall a b n, (lxor a b).[n] = xorb a.[n] b.[n].
+ Axiom div2_spec : forall a, div2 a == a >> 1.
+
+End NZBitsSpec.
+
+Module Type NZBits (A:NZOrdAxiomsSig) := Bits A <+ NZBitsSpec A.
+Module Type NZBits' (A:NZOrdAxiomsSig) := Bits' A <+ NZBitsSpec A.
+
+(** In the functor of properties will also be defined:
+ - [setbit : t -> t -> t ] defined as [lor a (1<<n)].
+ - [clearbit : t -> t -> t ] defined as [ldiff a (1<<n)].
+ - [ones : t -> t], the number with [n] initial true bits,
+ corresponding to [2^n - 1].
+ - a logical complement [lnot]. For integer numbers it will
+ be a [t->t], doing a swap of all bits, while on natural
+ numbers, it will be a bounded complement [t->t->t], swapping
+ only the first [n] bits.
+*)
+
+(** For the moment, no shared properties about NZ here,
+ since properties and proofs for N and Z are quite different *)
diff --git a/theories/Numbers/NatInt/NZDiv.v b/theories/Numbers/NatInt/NZDiv.v
index ba1c171e..bc109ace 100644
--- a/theories/Numbers/NatInt/NZDiv.v
+++ b/theories/Numbers/NatInt/NZDiv.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -12,44 +12,36 @@ Require Import NZAxioms NZMulOrder.
(** The first signatures will be common to all divisions over NZ, N and Z *)
-Module Type DivMod (Import T:Typ).
+Module Type DivMod (Import A : Typ).
Parameters Inline div modulo : t -> t -> t.
End DivMod.
-Module Type DivModNotation (T:Typ)(Import NZ:DivMod T).
+Module Type DivModNotation (A : Typ)(Import B : DivMod A).
Infix "/" := div.
Infix "mod" := modulo (at level 40, no associativity).
End DivModNotation.
-Module Type DivMod' (T:Typ) := DivMod T <+ DivModNotation T.
+Module Type DivMod' (A : Typ) := DivMod A <+ DivModNotation A.
-Module Type NZDivCommon (Import NZ : NZAxiomsSig')(Import DM : DivMod' NZ).
+Module Type NZDivSpec (Import A : NZOrdAxiomsSig')(Import B : DivMod' A).
Declare Instance div_wd : Proper (eq==>eq==>eq) div.
Declare Instance mod_wd : Proper (eq==>eq==>eq) modulo.
Axiom div_mod : forall a b, b ~= 0 -> a == b*(a/b) + (a mod b).
-End NZDivCommon.
+ Axiom mod_bound_pos : forall a b, 0<=a -> 0<b -> 0 <= a mod b < b.
+End NZDivSpec.
(** The different divisions will only differ in the conditions
- they impose on [modulo]. For NZ, we only describe behavior
- on positive numbers.
-
- NB: This axiom would also be true for N and Z, but redundant.
+ they impose on [modulo]. For NZ, we have only described the
+ behavior on positive numbers.
*)
-Module Type NZDivSpecific (Import NZ : NZOrdAxiomsSig')(Import DM : DivMod' NZ).
- Axiom mod_bound : forall a b, 0<=a -> 0<b -> 0 <= a mod b < b.
-End NZDivSpecific.
-
-Module Type NZDiv (NZ:NZOrdAxiomsSig)
- := DivMod NZ <+ NZDivCommon NZ <+ NZDivSpecific NZ.
+Module Type NZDiv (A : NZOrdAxiomsSig) := DivMod A <+ NZDivSpec A.
+Module Type NZDiv' (A : NZOrdAxiomsSig) := NZDiv A <+ DivModNotation A.
-Module Type NZDiv' (NZ:NZOrdAxiomsSig) := NZDiv NZ <+ DivModNotation NZ.
-
-Module NZDivPropFunct
- (Import NZ : NZOrdAxiomsSig')
- (Import NZP : NZMulOrderPropSig NZ)
- (Import NZD : NZDiv' NZ)
-.
+Module Type NZDivProp
+ (Import A : NZOrdAxiomsSig')
+ (Import B : NZDiv' A)
+ (Import C : NZMulOrderProp A).
(** Uniqueness theorems *)
@@ -84,7 +76,7 @@ Theorem div_unique:
Proof.
intros a b q r Ha (Hb,Hr) EQ.
destruct (div_mod_unique b q (a/b) r (a mod b)); auto.
-apply mod_bound; order.
+apply mod_bound_pos; order.
rewrite <- div_mod; order.
Qed.
@@ -94,18 +86,21 @@ Theorem mod_unique:
Proof.
intros a b q r Ha (Hb,Hr) EQ.
destruct (div_mod_unique b q (a/b) r (a mod b)); auto.
-apply mod_bound; order.
+apply mod_bound_pos; order.
rewrite <- div_mod; order.
Qed.
+Theorem div_unique_exact a b q:
+ 0<=a -> 0<b -> a == b*q -> q == a/b.
+Proof.
+ intros Ha Hb H. apply div_unique with 0; nzsimpl; now try split.
+Qed.
(** A division by itself returns 1 *)
Lemma div_same : forall a, 0<a -> a/a == 1.
Proof.
-intros. symmetry.
-apply div_unique with 0; intuition; try order.
-now nzsimpl.
+intros. symmetry. apply div_unique_exact; nzsimpl; order.
Qed.
Lemma mod_same : forall a, 0<a -> a mod a == 0.
@@ -147,9 +142,7 @@ Qed.
Lemma div_1_r: forall a, 0<=a -> a/1 == a.
Proof.
-intros. symmetry.
-apply div_unique with 0; try split; try order; try apply lt_0_1.
-now nzsimpl.
+intros. symmetry. apply div_unique_exact; nzsimpl; order'.
Qed.
Lemma mod_1_r: forall a, 0<=a -> a mod 1 == 0.
@@ -161,20 +154,19 @@ Qed.
Lemma div_1_l: forall a, 1<a -> 1/a == 0.
Proof.
-intros; apply div_small; split; auto. apply le_succ_diag_r.
+intros; apply div_small; split; auto. apply le_0_1.
Qed.
Lemma mod_1_l: forall a, 1<a -> 1 mod a == 1.
Proof.
-intros; apply mod_small; split; auto. apply le_succ_diag_r.
+intros; apply mod_small; split; auto. apply le_0_1.
Qed.
Lemma div_mul : forall a b, 0<=a -> 0<b -> (a*b)/b == a.
Proof.
-intros; symmetry.
-apply div_unique with 0; try split; try order.
+intros; symmetry. apply div_unique_exact; trivial.
apply mul_nonneg_nonneg; order.
-nzsimpl; apply mul_comm.
+apply mul_comm.
Qed.
Lemma mod_mul : forall a b, 0<=a -> 0<b -> (a*b) mod b == 0.
@@ -194,7 +186,7 @@ Theorem mod_le: forall a b, 0<=a -> 0<b -> a mod b <= a.
Proof.
intros. destruct (le_gt_cases b a).
apply le_trans with b; auto.
-apply lt_le_incl. destruct (mod_bound a b); auto.
+apply lt_le_incl. destruct (mod_bound_pos a b); auto.
rewrite lt_eq_cases; right.
apply mod_small; auto.
Qed.
@@ -216,7 +208,7 @@ Lemma div_str_pos : forall a b, 0<b<=a -> 0 < a/b.
Proof.
intros a b (Hb,Hab).
assert (LE : 0 <= a/b) by (apply div_pos; order).
-assert (MOD : a mod b < b) by (destruct (mod_bound a b); order).
+assert (MOD : a mod b < b) by (destruct (mod_bound_pos a b); order).
rewrite lt_eq_cases in LE; destruct LE as [LT|EQ]; auto.
exfalso; revert Hab.
rewrite (div_mod a b), <-EQ; nzsimpl; order.
@@ -263,7 +255,7 @@ rewrite <- (mul_1_l (a/b)) at 1.
rewrite <- mul_lt_mono_pos_r; auto.
apply div_str_pos; auto.
rewrite <- (add_0_r (b*(a/b))) at 1.
-rewrite <- add_le_mono_l. destruct (mod_bound a b); order.
+rewrite <- add_le_mono_l. destruct (mod_bound_pos a b); order.
Qed.
(** [le] is compatible with a positive division. *)
@@ -282,8 +274,8 @@ apply lt_le_trans with b; auto.
rewrite (div_mod b c) at 1 by order.
rewrite <- add_assoc, <- add_le_mono_l.
apply le_trans with (c+0).
-nzsimpl; destruct (mod_bound b c); order.
-rewrite <- add_le_mono_l. destruct (mod_bound a c); order.
+nzsimpl; destruct (mod_bound_pos b c); order.
+rewrite <- add_le_mono_l. destruct (mod_bound_pos a c); order.
Qed.
(** The following two properties could be used as specification of div *)
@@ -293,7 +285,7 @@ Proof.
intros.
rewrite (add_le_mono_r _ _ (a mod b)), <- div_mod by order.
rewrite <- (add_0_r a) at 1.
-rewrite <- add_le_mono_l. destruct (mod_bound a b); order.
+rewrite <- add_le_mono_l. destruct (mod_bound_pos a b); order.
Qed.
Lemma mul_succ_div_gt : forall a b, 0<=a -> 0<b -> a < b*(S (a/b)).
@@ -302,7 +294,7 @@ intros.
rewrite (div_mod a b) at 1 by order.
rewrite (mul_succ_r).
rewrite <- add_lt_mono_l.
-destruct (mod_bound a b); auto.
+destruct (mod_bound_pos a b); auto.
Qed.
@@ -359,7 +351,7 @@ Proof.
apply mul_le_mono_nonneg_r; try order.
apply div_pos; order.
rewrite <- (add_0_r (r*(p/r))) at 1.
- rewrite <- add_le_mono_l. destruct (mod_bound p r); order.
+ rewrite <- add_le_mono_l. destruct (mod_bound_pos p r); order.
Qed.
@@ -371,7 +363,7 @@ Proof.
intros.
symmetry.
apply mod_unique with (a/c+b); auto.
- apply mod_bound; auto.
+ apply mod_bound_pos; auto.
rewrite mul_add_distr_l, add_shuffle0, <- div_mod by order.
now rewrite mul_comm.
Qed.
@@ -404,8 +396,8 @@ Proof.
apply div_unique with ((a mod b)*c).
apply mul_nonneg_nonneg; order.
split.
- apply mul_nonneg_nonneg; destruct (mod_bound a b); order.
- rewrite <- mul_lt_mono_pos_r; auto. destruct (mod_bound a b); auto.
+ apply mul_nonneg_nonneg; destruct (mod_bound_pos a b); order.
+ rewrite <- mul_lt_mono_pos_r; auto. destruct (mod_bound_pos a b); auto.
rewrite (div_mod a b) at 1 by order.
rewrite mul_add_distr_r.
rewrite add_cancel_r.
@@ -441,7 +433,7 @@ Qed.
Theorem mod_mod: forall a n, 0<=a -> 0<n ->
(a mod n) mod n == a mod n.
Proof.
- intros. destruct (mod_bound a n); auto. now rewrite mod_small_iff.
+ intros. destruct (mod_bound_pos a n); auto. now rewrite mod_small_iff.
Qed.
Lemma mul_mod_idemp_l : forall a b n, 0<=a -> 0<=b -> 0<n ->
@@ -454,7 +446,7 @@ Proof.
rewrite mul_add_distr_l, mul_assoc.
intros. rewrite mod_add; auto.
now rewrite mul_comm.
- apply mul_nonneg_nonneg; destruct (mod_bound a n); auto.
+ apply mul_nonneg_nonneg; destruct (mod_bound_pos a n); auto.
Qed.
Lemma mul_mod_idemp_r : forall a b n, 0<=a -> 0<=b -> 0<n ->
@@ -467,7 +459,7 @@ Theorem mul_mod: forall a b n, 0<=a -> 0<=b -> 0<n ->
(a * b) mod n == ((a mod n) * (b mod n)) mod n.
Proof.
intros. rewrite mul_mod_idemp_l, mul_mod_idemp_r; trivial. reflexivity.
- now destruct (mod_bound b n).
+ now destruct (mod_bound_pos b n).
Qed.
Lemma add_mod_idemp_l : forall a b n, 0<=a -> 0<=b -> 0<n ->
@@ -478,7 +470,7 @@ Proof.
rewrite (div_mod a n) at 1 2 by order.
rewrite <- add_assoc, add_comm, mul_comm.
intros. rewrite mod_add; trivial. reflexivity.
- apply add_nonneg_nonneg; auto. destruct (mod_bound a n); auto.
+ apply add_nonneg_nonneg; auto. destruct (mod_bound_pos a n); auto.
Qed.
Lemma add_mod_idemp_r : forall a b n, 0<=a -> 0<=b -> 0<n ->
@@ -491,7 +483,7 @@ Theorem add_mod: forall a b n, 0<=a -> 0<=b -> 0<n ->
(a+b) mod n == (a mod n + b mod n) mod n.
Proof.
intros. rewrite add_mod_idemp_l, add_mod_idemp_r; trivial. reflexivity.
- now destruct (mod_bound b n).
+ now destruct (mod_bound_pos b n).
Qed.
Lemma div_div : forall a b c, 0<=a -> 0<b -> 0<c ->
@@ -500,7 +492,7 @@ Proof.
intros a b c Ha Hb Hc.
apply div_unique with (b*((a/b) mod c) + a mod b); trivial.
(* begin 0<= ... <b*c *)
- destruct (mod_bound (a/b) c), (mod_bound a b); auto using div_pos.
+ destruct (mod_bound_pos (a/b) c), (mod_bound_pos a b); auto using div_pos.
split.
apply add_nonneg_nonneg; auto.
apply mul_nonneg_nonneg; order.
@@ -514,6 +506,18 @@ Proof.
apply div_mod; order.
Qed.
+Lemma mod_mul_r : forall a b c, 0<=a -> 0<b -> 0<c ->
+ a mod (b*c) == a mod b + b*((a/b) mod c).
+Proof.
+ intros a b c Ha Hb Hc.
+ apply add_cancel_l with (b*c*(a/(b*c))).
+ rewrite <- div_mod by (apply neq_mul_0; split; order).
+ rewrite <- div_div by trivial.
+ rewrite add_assoc, add_shuffle0, <- mul_assoc, <- mul_add_distr_l.
+ rewrite <- div_mod by order.
+ apply div_mod; order.
+Qed.
+
(** A last inequality: *)
Theorem div_mul_le:
@@ -538,5 +542,5 @@ Proof.
rewrite (mul_le_mono_pos_l _ _ b); auto. nzsimpl. order.
Qed.
-End NZDivPropFunct.
+End NZDivProp.
diff --git a/theories/Numbers/NatInt/NZDomain.v b/theories/Numbers/NatInt/NZDomain.v
index 9dba3c3c..36aaa3e7 100644
--- a/theories/Numbers/NatInt/NZDomain.v
+++ b/theories/Numbers/NatInt/NZDomain.v
@@ -1,13 +1,11 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: NZDomain.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NumPrelude NZAxioms.
Require Import NZBase NZOrder NZAddOrder Plus Minus.
@@ -16,97 +14,36 @@ Require Import NZBase NZOrder NZAddOrder Plus Minus.
translation from Peano numbers [nat] into NZ.
*)
-(** First, a section about iterating a function. *)
-
-Section Iter.
-Variable A : Type.
-Fixpoint iter (f:A->A)(n:nat) : A -> A := fun a =>
- match n with
- | O => a
- | S n => f (iter f n a)
- end.
-Infix "^" := iter.
-
-Lemma iter_alt : forall f n m, (f^(Datatypes.S n)) m = (f^n) (f m).
-Proof.
-induction n; simpl; auto.
-intros; rewrite <- IHn; auto.
-Qed.
-
-Lemma iter_plus : forall f n n' m, (f^(n+n')) m = (f^n) ((f^n') m).
-Proof.
-induction n; simpl; auto.
-intros; rewrite IHn; auto.
-Qed.
+(** First, some complements about [nat_iter] *)
-Lemma iter_plus_bis : forall f n n' m, (f^(n+n')) m = (f^n') ((f^n) m).
-Proof.
-induction n; simpl; auto.
-intros. rewrite <- iter_alt, IHn; auto.
-Qed.
+Local Notation "f ^ n" := (nat_iter n f).
-Global Instance iter_wd (R:relation A) : Proper ((R==>R)==>eq==>R==>R) iter.
+Instance nat_iter_wd n {A} (R:relation A) :
+ Proper ((R==>R)==>R==>R) (nat_iter n).
Proof.
-intros f f' Hf n n' Hn; subst n'. induction n; simpl; red; auto.
+intros f f' Hf. induction n; simpl; red; auto.
Qed.
-End Iter.
-Implicit Arguments iter [A].
-Local Infix "^" := iter.
-
-
Module NZDomainProp (Import NZ:NZDomainSig').
+Include NZBaseProp NZ.
(** * Relationship between points thanks to [succ] and [pred]. *)
-(** We prove that any points in NZ have a common descendant by [succ] *)
-
-Definition common_descendant n m := exists k, exists l, (S^k) n == (S^l) m.
-
-Instance common_descendant_wd : Proper (eq==>eq==>iff) common_descendant.
-Proof.
-unfold common_descendant. intros n n' Hn m m' Hm.
-setoid_rewrite Hn. setoid_rewrite Hm. auto with *.
-Qed.
-
-Instance common_descendant_equiv : Equivalence common_descendant.
-Proof.
-split; red.
-intros x. exists O; exists O. simpl; auto with *.
-intros x y (p & q & H); exists q; exists p; auto with *.
-intros x y z (p & q & Hpq) (r & s & Hrs).
-exists (r+p)%nat. exists (q+s)%nat.
-rewrite !iter_plus. rewrite Hpq, <-Hrs, <-iter_plus, <- iter_plus_bis.
-auto with *.
-Qed.
-
-Lemma common_descendant_with_0 : forall n, common_descendant n 0.
-Proof.
-apply bi_induction.
-intros n n' Hn. rewrite Hn; auto with *.
-reflexivity.
-split; intros (p & q & H).
-exists p; exists (Datatypes.S q). rewrite <- iter_alt; simpl.
- apply succ_wd; auto.
-exists (Datatypes.S p); exists q. rewrite iter_alt; auto.
-Qed.
-
-Lemma common_descendant_always : forall n m, common_descendant n m.
-Proof.
-intros. transitivity 0; [|symmetry]; apply common_descendant_with_0.
-Qed.
-
-(** Thanks to [succ] being injective, we can then deduce that for any two
- points, one is an iterated successor of the other. *)
+(** For any two points, one is an iterated successor of the other. *)
-Lemma itersucc_or_itersucc : forall n m, exists k, n == (S^k) m \/ m == (S^k) n.
+Lemma itersucc_or_itersucc n m : exists k, n == (S^k) m \/ m == (S^k) n.
Proof.
-intros n m. destruct (common_descendant_always n m) as (k & l & H).
-revert l H. induction k.
-simpl. intros; exists l; left; auto with *.
-intros. destruct l.
-simpl in *. exists (Datatypes.S k); right; auto with *.
-simpl in *. apply pred_wd in H; rewrite !pred_succ in H. eauto.
+nzinduct n m.
+exists 0%nat. now left.
+intros n. split; intros [k [L|R]].
+exists (Datatypes.S k). left. now apply succ_wd.
+destruct k as [|k].
+simpl in R. exists 1%nat. left. now apply succ_wd.
+rewrite nat_iter_succ_r in R. exists k. now right.
+destruct k as [|k]; simpl in L.
+exists 1%nat. now right.
+apply succ_inj in L. exists k. now left.
+exists (Datatypes.S k). right. now rewrite nat_iter_succ_r.
Qed.
(** Generalized version of [pred_succ] when iterating *)
@@ -116,7 +53,7 @@ Proof.
induction k.
simpl; auto with *.
simpl; intros. apply pred_wd in H. rewrite pred_succ in H. apply IHk in H; auto.
-rewrite <- iter_alt in H; auto.
+rewrite <- nat_iter_succ_r in H; auto.
Qed.
(** From a given point, all others are iterated successors
@@ -307,7 +244,7 @@ End NZOfNat.
Module NZOfNatOrd (Import NZ:NZOrdSig').
Include NZOfNat NZ.
-Include NZOrderPropFunct NZ.
+Include NZBaseProp NZ <+ NZOrderProp NZ.
Local Open Scope ofnat.
Theorem ofnat_S_gt_0 :
@@ -315,8 +252,8 @@ Theorem ofnat_S_gt_0 :
Proof.
unfold ofnat.
intros n; induction n as [| n IH]; simpl in *.
-apply lt_0_1.
-apply lt_trans with 1. apply lt_0_1. now rewrite <- succ_lt_mono.
+apply lt_succ_diag_r.
+apply lt_trans with (S 0). apply lt_succ_diag_r. now rewrite <- succ_lt_mono.
Qed.
Theorem ofnat_S_neq_0 :
@@ -375,14 +312,14 @@ Lemma ofnat_add_l : forall n m, [n]+m == (S^n) m.
Proof.
induction n; intros.
apply add_0_l.
- rewrite ofnat_succ, add_succ_l. simpl; apply succ_wd; auto.
+ rewrite ofnat_succ, add_succ_l. simpl. now f_equiv.
Qed.
Lemma ofnat_add : forall n m, [n+m] == [n]+[m].
Proof.
intros. rewrite ofnat_add_l.
induction n; simpl. reflexivity.
- rewrite ofnat_succ. now apply succ_wd.
+ rewrite ofnat_succ. now f_equiv.
Qed.
Lemma ofnat_mul : forall n m, [n*m] == [n]*[m].
@@ -391,14 +328,14 @@ Proof.
symmetry. apply mul_0_l.
rewrite plus_comm.
rewrite ofnat_succ, ofnat_add, mul_succ_l.
- now apply add_wd.
+ now f_equiv.
Qed.
Lemma ofnat_sub_r : forall n m, n-[m] == (P^m) n.
Proof.
induction m; simpl; intros.
rewrite ofnat_zero. apply sub_0_r.
- rewrite ofnat_succ, sub_succ_r. now apply pred_wd.
+ rewrite ofnat_succ, sub_succ_r. now f_equiv.
Qed.
Lemma ofnat_sub : forall n m, m<=n -> [n-m] == [n]-[m].
@@ -409,7 +346,7 @@ Proof.
intros.
destruct n.
inversion H.
- rewrite iter_alt.
+ rewrite nat_iter_succ_r.
simpl.
rewrite ofnat_succ, pred_succ; auto with arith.
Qed.
diff --git a/theories/Numbers/NatInt/NZGcd.v b/theories/Numbers/NatInt/NZGcd.v
new file mode 100644
index 00000000..f72023d9
--- /dev/null
+++ b/theories/Numbers/NatInt/NZGcd.v
@@ -0,0 +1,307 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Greatest Common Divisor *)
+
+Require Import NZAxioms NZMulOrder.
+
+(** Interface of a gcd function, then its specification on naturals *)
+
+Module Type Gcd (Import A : Typ).
+ Parameter Inline gcd : t -> t -> t.
+End Gcd.
+
+Module Type NZGcdSpec (A : NZOrdAxiomsSig')(B : Gcd A).
+ Import A B.
+ Definition divide n m := exists p, m == p*n.
+ Local Notation "( n | m )" := (divide n m) (at level 0).
+ Axiom gcd_divide_l : forall n m, (gcd n m | n).
+ Axiom gcd_divide_r : forall n m, (gcd n m | m).
+ Axiom gcd_greatest : forall n m p, (p | n) -> (p | m) -> (p | gcd n m).
+ Axiom gcd_nonneg : forall n m, 0 <= gcd n m.
+End NZGcdSpec.
+
+Module Type DivideNotation (A:NZOrdAxiomsSig')(B:Gcd A)(C:NZGcdSpec A B).
+ Import A B C.
+ Notation "( n | m )" := (divide n m) (at level 0).
+End DivideNotation.
+
+Module Type NZGcd (A : NZOrdAxiomsSig) := Gcd A <+ NZGcdSpec A.
+Module Type NZGcd' (A : NZOrdAxiomsSig) :=
+ Gcd A <+ NZGcdSpec A <+ DivideNotation A.
+
+(** Derived properties of gcd *)
+
+Module NZGcdProp
+ (Import A : NZOrdAxiomsSig')
+ (Import B : NZGcd' A)
+ (Import C : NZMulOrderProp A).
+
+(** Results concerning divisibility*)
+
+Instance divide_wd : Proper (eq==>eq==>iff) divide.
+Proof.
+ unfold divide. intros x x' Hx y y' Hy.
+ setoid_rewrite Hx. setoid_rewrite Hy. easy.
+Qed.
+
+Lemma divide_1_l : forall n, (1 | n).
+Proof.
+ intros n. exists n. now nzsimpl.
+Qed.
+
+Lemma divide_0_r : forall n, (n | 0).
+Proof.
+ intros n. exists 0. now nzsimpl.
+Qed.
+
+Hint Rewrite divide_1_l divide_0_r : nz.
+
+Lemma divide_0_l : forall n, (0 | n) -> n==0.
+Proof.
+ intros n (m,Hm). revert Hm. now nzsimpl.
+Qed.
+
+Lemma eq_mul_1_nonneg : forall n m,
+ 0<=n -> n*m == 1 -> n==1 /\ m==1.
+Proof.
+ intros n m Hn H.
+ le_elim Hn.
+ destruct (lt_ge_cases m 0) as [Hm|Hm].
+ generalize (mul_pos_neg n m Hn Hm). order'.
+ le_elim Hm.
+ apply le_succ_l in Hn. rewrite <- one_succ in Hn.
+ le_elim Hn.
+ generalize (lt_1_mul_pos n m Hn Hm). order.
+ rewrite <- Hn, mul_1_l in H. now split.
+ rewrite <- Hm, mul_0_r in H. order'.
+ rewrite <- Hn, mul_0_l in H. order'.
+Qed.
+
+Lemma eq_mul_1_nonneg' : forall n m,
+ 0<=m -> n*m == 1 -> n==1 /\ m==1.
+Proof.
+ intros n m Hm H. rewrite mul_comm in H.
+ now apply and_comm, eq_mul_1_nonneg.
+Qed.
+
+Lemma divide_1_r_nonneg : forall n, 0<=n -> (n | 1) -> n==1.
+Proof.
+ intros n Hn (m,Hm). symmetry in Hm.
+ now apply (eq_mul_1_nonneg' m n).
+Qed.
+
+Lemma divide_refl : forall n, (n | n).
+Proof.
+ intros n. exists 1. now nzsimpl.
+Qed.
+
+Lemma divide_trans : forall n m p, (n | m) -> (m | p) -> (n | p).
+Proof.
+ intros n m p (q,Hq) (r,Hr). exists (r*q).
+ now rewrite Hr, Hq, mul_assoc.
+Qed.
+
+Instance divide_reflexive : Reflexive divide := divide_refl.
+Instance divide_transitive : Transitive divide := divide_trans.
+
+(** Due to sign, no general antisymmetry result *)
+
+Lemma divide_antisym_nonneg : forall n m,
+ 0<=n -> 0<=m -> (n | m) -> (m | n) -> n == m.
+Proof.
+ intros n m Hn Hm (q,Hq) (r,Hr).
+ le_elim Hn.
+ destruct (lt_ge_cases q 0) as [Hq'|Hq'].
+ generalize (mul_neg_pos q n Hq' Hn). order.
+ rewrite Hq, mul_assoc in Hr. symmetry in Hr.
+ apply mul_id_l in Hr; [|order].
+ destruct (eq_mul_1_nonneg' r q) as [_ H]; trivial.
+ now rewrite H, mul_1_l in Hq.
+ rewrite <- Hn, mul_0_r in Hq. now rewrite <- Hn.
+Qed.
+
+Lemma mul_divide_mono_l : forall n m p, (n | m) -> (p * n | p * m).
+Proof.
+ intros n m p (q,Hq). exists q. now rewrite mul_shuffle3, Hq.
+Qed.
+
+Lemma mul_divide_mono_r : forall n m p, (n | m) -> (n * p | m * p).
+Proof.
+ intros n m p (q,Hq). exists q. now rewrite mul_assoc, Hq.
+Qed.
+
+Lemma mul_divide_cancel_l : forall n m p, p ~= 0 ->
+ ((p * n | p * m) <-> (n | m)).
+Proof.
+ intros n m p Hp. split.
+ intros (q,Hq). exists q. now rewrite mul_shuffle3, mul_cancel_l in Hq.
+ apply mul_divide_mono_l.
+Qed.
+
+Lemma mul_divide_cancel_r : forall n m p, p ~= 0 ->
+ ((n * p | m * p) <-> (n | m)).
+Proof.
+ intros. rewrite 2 (mul_comm _ p). now apply mul_divide_cancel_l.
+Qed.
+
+Lemma divide_add_r : forall n m p, (n | m) -> (n | p) -> (n | m + p).
+Proof.
+ intros n m p (q,Hq) (r,Hr). exists (q+r).
+ now rewrite mul_add_distr_r, Hq, Hr.
+Qed.
+
+Lemma divide_mul_l : forall n m p, (n | m) -> (n | m * p).
+Proof.
+ intros n m p (q,Hq). exists (q*p). now rewrite mul_shuffle0, Hq.
+Qed.
+
+Lemma divide_mul_r : forall n m p, (n | p) -> (n | m * p).
+Proof.
+ intros n m p. rewrite mul_comm. apply divide_mul_l.
+Qed.
+
+Lemma divide_factor_l : forall n m, (n | n * m).
+Proof.
+ intros. apply divide_mul_l, divide_refl.
+Qed.
+
+Lemma divide_factor_r : forall n m, (n | m * n).
+Proof.
+ intros. apply divide_mul_r, divide_refl.
+Qed.
+
+Lemma divide_pos_le : forall n m, 0 < m -> (n | m) -> n <= m.
+Proof.
+ intros n m Hm (q,Hq).
+ destruct (le_gt_cases n 0) as [Hn|Hn]. order.
+ rewrite Hq.
+ destruct (lt_ge_cases q 0) as [Hq'|Hq'].
+ generalize (mul_neg_pos q n Hq' Hn). order.
+ le_elim Hq'.
+ rewrite <- (mul_1_l n) at 1. apply mul_le_mono_pos_r; trivial.
+ now rewrite one_succ, le_succ_l.
+ rewrite <- Hq', mul_0_l in Hq. order.
+Qed.
+
+(** Basic properties of gcd *)
+
+Lemma gcd_unique : forall n m p,
+ 0<=p -> (p|n) -> (p|m) ->
+ (forall q, (q|n) -> (q|m) -> (q|p)) ->
+ gcd n m == p.
+Proof.
+ intros n m p Hp Hn Hm H.
+ apply divide_antisym_nonneg; trivial. apply gcd_nonneg.
+ apply H. apply gcd_divide_l. apply gcd_divide_r.
+ now apply gcd_greatest.
+Qed.
+
+Instance gcd_wd : Proper (eq==>eq==>eq) gcd.
+Proof.
+ intros x x' Hx y y' Hy.
+ apply gcd_unique.
+ apply gcd_nonneg.
+ rewrite Hx. apply gcd_divide_l.
+ rewrite Hy. apply gcd_divide_r.
+ intro. rewrite Hx, Hy. apply gcd_greatest.
+Qed.
+
+Lemma gcd_divide_iff : forall n m p,
+ (p | gcd n m) <-> (p | n) /\ (p | m).
+Proof.
+ intros. split. split.
+ transitivity (gcd n m); trivial using gcd_divide_l.
+ transitivity (gcd n m); trivial using gcd_divide_r.
+ intros (H,H'). now apply gcd_greatest.
+Qed.
+
+Lemma gcd_unique_alt : forall n m p, 0<=p ->
+ (forall q, (q|p) <-> (q|n) /\ (q|m)) ->
+ gcd n m == p.
+Proof.
+ intros n m p Hp H.
+ apply gcd_unique; trivial.
+ apply H. apply divide_refl.
+ apply H. apply divide_refl.
+ intros. apply H. now split.
+Qed.
+
+Lemma gcd_comm : forall n m, gcd n m == gcd m n.
+Proof.
+ intros. apply gcd_unique_alt; try apply gcd_nonneg.
+ intros. rewrite and_comm. apply gcd_divide_iff.
+Qed.
+
+Lemma gcd_assoc : forall n m p, gcd n (gcd m p) == gcd (gcd n m) p.
+Proof.
+ intros. apply gcd_unique_alt; try apply gcd_nonneg.
+ intros. now rewrite !gcd_divide_iff, and_assoc.
+Qed.
+
+Lemma gcd_0_l_nonneg : forall n, 0<=n -> gcd 0 n == n.
+Proof.
+ intros. apply gcd_unique; trivial.
+ apply divide_0_r.
+ apply divide_refl.
+Qed.
+
+Lemma gcd_0_r_nonneg : forall n, 0<=n -> gcd n 0 == n.
+Proof.
+ intros. now rewrite gcd_comm, gcd_0_l_nonneg.
+Qed.
+
+Lemma gcd_1_l : forall n, gcd 1 n == 1.
+Proof.
+ intros. apply gcd_unique; trivial using divide_1_l, le_0_1.
+Qed.
+
+Lemma gcd_1_r : forall n, gcd n 1 == 1.
+Proof.
+ intros. now rewrite gcd_comm, gcd_1_l.
+Qed.
+
+Lemma gcd_diag_nonneg : forall n, 0<=n -> gcd n n == n.
+Proof.
+ intros. apply gcd_unique; trivial using divide_refl.
+Qed.
+
+Lemma gcd_eq_0_l : forall n m, gcd n m == 0 -> n == 0.
+Proof.
+ intros.
+ generalize (gcd_divide_l n m). rewrite H. apply divide_0_l.
+Qed.
+
+Lemma gcd_eq_0_r : forall n m, gcd n m == 0 -> m == 0.
+Proof.
+ intros. apply gcd_eq_0_l with n. now rewrite gcd_comm.
+Qed.
+
+Lemma gcd_eq_0 : forall n m, gcd n m == 0 <-> n == 0 /\ m == 0.
+Proof.
+ intros. split. split.
+ now apply gcd_eq_0_l with m.
+ now apply gcd_eq_0_r with n.
+ intros (EQ,EQ'). rewrite EQ, EQ'. now apply gcd_0_r_nonneg.
+Qed.
+
+Lemma gcd_mul_diag_l : forall n m, 0<=n -> gcd n (n*m) == n.
+Proof.
+ intros n m Hn. apply gcd_unique_alt; trivial.
+ intros q. split. split; trivial. now apply divide_mul_l.
+ now destruct 1.
+Qed.
+
+Lemma divide_gcd_iff : forall n m, 0<=n -> ((n|m) <-> gcd n m == n).
+Proof.
+ intros n m Hn. split. intros (q,Hq). rewrite Hq.
+ rewrite mul_comm. now apply gcd_mul_diag_l.
+ intros EQ. rewrite <- EQ. apply gcd_divide_r.
+Qed.
+
+End NZGcdProp.
diff --git a/theories/Numbers/NatInt/NZLog.v b/theories/Numbers/NatInt/NZLog.v
new file mode 100644
index 00000000..a5aa6d8a
--- /dev/null
+++ b/theories/Numbers/NatInt/NZLog.v
@@ -0,0 +1,889 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Base-2 Logarithm *)
+
+Require Import NZAxioms NZMulOrder NZPow.
+
+(** Interface of a log2 function, then its specification on naturals *)
+
+Module Type Log2 (Import A : Typ).
+ Parameter Inline log2 : t -> t.
+End Log2.
+
+Module Type NZLog2Spec (A : NZOrdAxiomsSig')(B : Pow' A)(C : Log2 A).
+ Import A B C.
+ Axiom log2_spec : forall a, 0<a -> 2^(log2 a) <= a < 2^(S (log2 a)).
+ Axiom log2_nonpos : forall a, a<=0 -> log2 a == 0.
+End NZLog2Spec.
+
+Module Type NZLog2 (A : NZOrdAxiomsSig)(B : Pow A) := Log2 A <+ NZLog2Spec A B.
+
+(** Derived properties of logarithm *)
+
+Module Type NZLog2Prop
+ (Import A : NZOrdAxiomsSig')
+ (Import B : NZPow' A)
+ (Import C : NZLog2 A B)
+ (Import D : NZMulOrderProp A)
+ (Import E : NZPowProp A B D).
+
+(** log2 is always non-negative *)
+
+Lemma log2_nonneg : forall a, 0 <= log2 a.
+Proof.
+ intros a. destruct (le_gt_cases a 0) as [Ha|Ha].
+ now rewrite log2_nonpos.
+ destruct (log2_spec a Ha) as (_,LT).
+ apply lt_succ_r, (pow_gt_1 2). order'.
+ rewrite <- le_succ_l, <- one_succ in Ha. order.
+Qed.
+
+(** A tactic for proving positivity and non-negativity *)
+
+Ltac order_pos :=
+((apply add_pos_pos || apply add_nonneg_nonneg ||
+ apply mul_pos_pos || apply mul_nonneg_nonneg ||
+ apply pow_nonneg || apply pow_pos_nonneg ||
+ apply log2_nonneg || apply (le_le_succ_r 0));
+ order_pos) (* in case of success of an apply, we recurse *)
+|| order'. (* otherwise *)
+
+(** The spec of log2 indeed determines it *)
+
+Lemma log2_unique : forall a b, 0<=b -> 2^b<=a<2^(S b) -> log2 a == b.
+Proof.
+ intros a b Hb (LEb,LTb).
+ assert (Ha : 0 < a).
+ apply lt_le_trans with (2^b); trivial.
+ apply pow_pos_nonneg; order'.
+ assert (Hc := log2_nonneg a).
+ destruct (log2_spec a Ha) as (LEc,LTc).
+ assert (log2 a <= b).
+ apply lt_succ_r, (pow_lt_mono_r_iff 2); try order'.
+ now apply le_le_succ_r.
+ assert (b <= log2 a).
+ apply lt_succ_r, (pow_lt_mono_r_iff 2); try order'.
+ now apply le_le_succ_r.
+ order.
+Qed.
+
+(** Hence log2 is a morphism. *)
+
+Instance log2_wd : Proper (eq==>eq) log2.
+Proof.
+ intros x x' Hx.
+ destruct (le_gt_cases x 0).
+ rewrite 2 log2_nonpos; trivial. reflexivity. now rewrite <- Hx.
+ apply log2_unique. apply log2_nonneg.
+ rewrite Hx in *. now apply log2_spec.
+Qed.
+
+(** An alternate specification *)
+
+Lemma log2_spec_alt : forall a, 0<a -> exists r,
+ a == 2^(log2 a) + r /\ 0 <= r < 2^(log2 a).
+Proof.
+ intros a Ha.
+ destruct (log2_spec _ Ha) as (LE,LT).
+ destruct (le_exists_sub _ _ LE) as (r & Hr & Hr').
+ exists r.
+ split. now rewrite add_comm.
+ split. trivial.
+ apply (add_lt_mono_r _ _ (2^log2 a)).
+ rewrite <- Hr. generalize LT.
+ rewrite pow_succ_r by order_pos.
+ rewrite two_succ at 1. now nzsimpl.
+Qed.
+
+Lemma log2_unique' : forall a b c, 0<=b -> 0<=c<2^b ->
+ a == 2^b + c -> log2 a == b.
+Proof.
+ intros a b c Hb (Hc,H) EQ.
+ apply log2_unique. trivial.
+ rewrite EQ.
+ split.
+ rewrite <- add_0_r at 1. now apply add_le_mono_l.
+ rewrite pow_succ_r by order.
+ rewrite two_succ at 2. nzsimpl. now apply add_lt_mono_l.
+Qed.
+
+(** log2 is exact on powers of 2 *)
+
+Lemma log2_pow2 : forall a, 0<=a -> log2 (2^a) == a.
+Proof.
+ intros a Ha.
+ apply log2_unique' with 0; trivial.
+ split; order_pos. now nzsimpl.
+Qed.
+
+(** log2 and predecessors of powers of 2 *)
+
+Lemma log2_pred_pow2 : forall a, 0<a -> log2 (P (2^a)) == P a.
+Proof.
+ intros a Ha.
+ assert (Ha' : S (P a) == a) by (now rewrite lt_succ_pred with 0).
+ apply log2_unique.
+ apply lt_succ_r; order.
+ rewrite <-le_succ_l, <-lt_succ_r, Ha'.
+ rewrite lt_succ_pred with 0.
+ split; try easy. apply pow_lt_mono_r_iff; try order'.
+ rewrite succ_lt_mono, Ha'. apply lt_succ_diag_r.
+ apply pow_pos_nonneg; order'.
+Qed.
+
+(** log2 and basic constants *)
+
+Lemma log2_1 : log2 1 == 0.
+Proof.
+ rewrite <- (pow_0_r 2). now apply log2_pow2.
+Qed.
+
+Lemma log2_2 : log2 2 == 1.
+Proof.
+ rewrite <- (pow_1_r 2). apply log2_pow2; order'.
+Qed.
+
+(** log2 n is strictly positive for 1<n *)
+
+Lemma log2_pos : forall a, 1<a -> 0 < log2 a.
+Proof.
+ intros a Ha.
+ assert (Ha' : 0 < a) by order'.
+ assert (H := log2_nonneg a). le_elim H; trivial.
+ generalize (log2_spec a Ha'). rewrite <- H in *. nzsimpl; try order.
+ intros (_,H'). rewrite two_succ in H'. apply lt_succ_r in H'; order.
+Qed.
+
+(** Said otherwise, log2 is null only below 1 *)
+
+Lemma log2_null : forall a, log2 a == 0 <-> a <= 1.
+Proof.
+ intros a. split; intros H.
+ destruct (le_gt_cases a 1) as [Ha|Ha]; trivial.
+ generalize (log2_pos a Ha); order.
+ le_elim H.
+ apply log2_nonpos. apply lt_succ_r. now rewrite <- one_succ.
+ rewrite H. apply log2_1.
+Qed.
+
+(** log2 is a monotone function (but not a strict one) *)
+
+Lemma log2_le_mono : forall a b, a<=b -> log2 a <= log2 b.
+Proof.
+ intros a b H.
+ destruct (le_gt_cases a 0) as [Ha|Ha].
+ rewrite log2_nonpos; order_pos.
+ assert (Hb : 0 < b) by order.
+ destruct (log2_spec a Ha) as (LEa,_).
+ destruct (log2_spec b Hb) as (_,LTb).
+ apply lt_succ_r, (pow_lt_mono_r_iff 2); order_pos.
+Qed.
+
+(** No reverse result for <=, consider for instance log2 3 <= log2 2 *)
+
+Lemma log2_lt_cancel : forall a b, log2 a < log2 b -> a < b.
+Proof.
+ intros a b H.
+ destruct (le_gt_cases b 0) as [Hb|Hb].
+ rewrite (log2_nonpos b) in H; trivial.
+ generalize (log2_nonneg a); order.
+ destruct (le_gt_cases a 0) as [Ha|Ha]. order.
+ destruct (log2_spec a Ha) as (_,LTa).
+ destruct (log2_spec b Hb) as (LEb,_).
+ apply le_succ_l in H.
+ apply (pow_le_mono_r_iff 2) in H; order_pos.
+Qed.
+
+(** When left side is a power of 2, we have an equivalence for <= *)
+
+Lemma log2_le_pow2 : forall a b, 0<a -> (2^b<=a <-> b <= log2 a).
+Proof.
+ intros a b Ha.
+ split; intros H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ generalize (log2_nonneg a); order.
+ rewrite <- (log2_pow2 b); trivial. now apply log2_le_mono.
+ transitivity (2^(log2 a)).
+ apply pow_le_mono_r; order'.
+ now destruct (log2_spec a Ha).
+Qed.
+
+(** When right side is a square, we have an equivalence for < *)
+
+Lemma log2_lt_pow2 : forall a b, 0<a -> (a<2^b <-> log2 a < b).
+Proof.
+ intros a b Ha.
+ split; intros H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite pow_neg_r in H; order.
+ apply (pow_lt_mono_r_iff 2); try order_pos.
+ apply le_lt_trans with a; trivial.
+ now destruct (log2_spec a Ha).
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ generalize (log2_nonneg a); order.
+ apply log2_lt_cancel; try order.
+ now rewrite log2_pow2.
+Qed.
+
+(** Comparing log2 and identity *)
+
+Lemma log2_lt_lin : forall a, 0<a -> log2 a < a.
+Proof.
+ intros a Ha.
+ apply (pow_lt_mono_r_iff 2); try order_pos.
+ apply le_lt_trans with a.
+ now destruct (log2_spec a Ha).
+ apply pow_gt_lin_r; order'.
+Qed.
+
+Lemma log2_le_lin : forall a, 0<=a -> log2 a <= a.
+Proof.
+ intros a Ha.
+ le_elim Ha.
+ now apply lt_le_incl, log2_lt_lin.
+ rewrite <- Ha, log2_nonpos; order.
+Qed.
+
+(** Log2 and multiplication. *)
+
+(** Due to rounding error, we don't have the usual
+ [log2 (a*b) = log2 a + log2 b] but we may be off by 1 at most *)
+
+Lemma log2_mul_below : forall a b, 0<a -> 0<b ->
+ log2 a + log2 b <= log2 (a*b).
+Proof.
+ intros a b Ha Hb.
+ apply log2_le_pow2; try order_pos.
+ rewrite pow_add_r by order_pos.
+ apply mul_le_mono_nonneg; try apply log2_spec; order_pos.
+Qed.
+
+Lemma log2_mul_above : forall a b, 0<=a -> 0<=b ->
+ log2 (a*b) <= log2 a + log2 b + 1.
+Proof.
+ intros a b Ha Hb.
+ le_elim Ha.
+ le_elim Hb.
+ apply lt_succ_r.
+ rewrite add_1_r, <- add_succ_r, <- add_succ_l.
+ apply log2_lt_pow2; try order_pos.
+ rewrite pow_add_r by order_pos.
+ apply mul_lt_mono_nonneg; try order; now apply log2_spec.
+ rewrite <- Hb. nzsimpl. rewrite log2_nonpos; order_pos.
+ rewrite <- Ha. nzsimpl. rewrite log2_nonpos; order_pos.
+Qed.
+
+(** And we can't find better approximations in general.
+ - The lower bound is exact for powers of 2.
+ - Concerning the upper bound, for any c>1, take a=b=2^c-1,
+ then log2 (a*b) = c+c -1 while (log2 a) = (log2 b) = c-1
+*)
+
+(** At least, we get back the usual equation when we multiply by 2 (or 2^k) *)
+
+Lemma log2_mul_pow2 : forall a b, 0<a -> 0<=b -> log2 (a*2^b) == b + log2 a.
+Proof.
+ intros a b Ha Hb.
+ apply log2_unique; try order_pos. split.
+ rewrite pow_add_r, mul_comm; try order_pos.
+ apply mul_le_mono_nonneg_r. order_pos. now apply log2_spec.
+ rewrite <-add_succ_r, pow_add_r, mul_comm; try order_pos.
+ apply mul_lt_mono_pos_l. order_pos. now apply log2_spec.
+Qed.
+
+Lemma log2_double : forall a, 0<a -> log2 (2*a) == S (log2 a).
+Proof.
+ intros a Ha. generalize (log2_mul_pow2 a 1 Ha le_0_1). now nzsimpl'.
+Qed.
+
+(** Two numbers with same log2 cannot be far away. *)
+
+Lemma log2_same : forall a b, 0<a -> 0<b -> log2 a == log2 b -> a < 2*b.
+Proof.
+ intros a b Ha Hb H.
+ apply log2_lt_cancel. rewrite log2_double, H by trivial.
+ apply lt_succ_diag_r.
+Qed.
+
+(** Log2 and successor :
+ - the log2 function climbs by at most 1 at a time
+ - otherwise it stays at the same value
+ - the +1 steps occur for powers of two
+*)
+
+Lemma log2_succ_le : forall a, log2 (S a) <= S (log2 a).
+Proof.
+ intros a.
+ destruct (lt_trichotomy 0 a) as [LT|[EQ|LT]].
+ apply (pow_le_mono_r_iff 2); try order_pos.
+ transitivity (S a).
+ apply log2_spec.
+ apply lt_succ_r; order.
+ now apply le_succ_l, log2_spec.
+ rewrite <- EQ, <- one_succ, log2_1; order_pos.
+ rewrite 2 log2_nonpos. order_pos. order'. now rewrite le_succ_l.
+Qed.
+
+Lemma log2_succ_or : forall a,
+ log2 (S a) == S (log2 a) \/ log2 (S a) == log2 a.
+Proof.
+ intros.
+ destruct (le_gt_cases (log2 (S a)) (log2 a)) as [H|H].
+ right. generalize (log2_le_mono _ _ (le_succ_diag_r a)); order.
+ left. apply le_succ_l in H. generalize (log2_succ_le a); order.
+Qed.
+
+Lemma log2_eq_succ_is_pow2 : forall a,
+ log2 (S a) == S (log2 a) -> exists b, S a == 2^b.
+Proof.
+ intros a H.
+ destruct (le_gt_cases a 0) as [Ha|Ha].
+ rewrite 2 (proj2 (log2_null _)) in H. generalize (lt_succ_diag_r 0); order.
+ order'. apply le_succ_l. order'.
+ assert (Ha' : 0 < S a) by (apply lt_succ_r; order).
+ exists (log2 (S a)).
+ generalize (proj1 (log2_spec (S a) Ha')) (proj2 (log2_spec a Ha)).
+ rewrite <- le_succ_l, <- H. order.
+Qed.
+
+Lemma log2_eq_succ_iff_pow2 : forall a, 0<a ->
+ (log2 (S a) == S (log2 a) <-> exists b, S a == 2^b).
+Proof.
+ intros a Ha.
+ split. apply log2_eq_succ_is_pow2.
+ intros (b,Hb).
+ assert (Hb' : 0 < b).
+ apply (pow_gt_1 2); try order'; now rewrite <- Hb, one_succ, <- succ_lt_mono.
+ rewrite Hb, log2_pow2; try order'.
+ setoid_replace a with (P (2^b)). rewrite log2_pred_pow2; trivial.
+ symmetry; now apply lt_succ_pred with 0.
+ apply succ_inj. rewrite Hb. symmetry. apply lt_succ_pred with 0.
+ rewrite <- Hb, lt_succ_r; order.
+Qed.
+
+Lemma log2_succ_double : forall a, 0<a -> log2 (2*a+1) == S (log2 a).
+Proof.
+ intros a Ha.
+ rewrite add_1_r.
+ destruct (log2_succ_or (2*a)) as [H|H]; [exfalso|now rewrite H, log2_double].
+ apply log2_eq_succ_is_pow2 in H. destruct H as (b,H).
+ destruct (lt_trichotomy b 0) as [LT|[EQ|LT]].
+ rewrite pow_neg_r in H; trivial.
+ apply (mul_pos_pos 2), succ_lt_mono in Ha; try order'.
+ rewrite <- one_succ in Ha. order'.
+ rewrite EQ, pow_0_r in H.
+ apply (mul_pos_pos 2), succ_lt_mono in Ha; try order'.
+ rewrite <- one_succ in Ha. order'.
+ assert (EQ:=lt_succ_pred 0 b LT).
+ rewrite <- EQ, pow_succ_r in H; [|now rewrite <- lt_succ_r, EQ].
+ destruct (lt_ge_cases a (2^(P b))) as [LT'|LE'].
+ generalize (mul_2_mono_l _ _ LT'). rewrite add_1_l. order.
+ rewrite (mul_le_mono_pos_l _ _ 2) in LE'; try order'.
+ rewrite <- H in LE'. apply le_succ_l in LE'. order.
+Qed.
+
+(** Log2 and addition *)
+
+Lemma log2_add_le : forall a b, a~=1 -> b~=1 -> log2 (a+b) <= log2 a + log2 b.
+Proof.
+ intros a b Ha Hb.
+ destruct (lt_trichotomy a 1) as [Ha'|[Ha'|Ha']]; [|order|].
+ rewrite one_succ, lt_succ_r in Ha'.
+ rewrite (log2_nonpos a); trivial. nzsimpl. apply log2_le_mono.
+ rewrite <- (add_0_l b) at 2. now apply add_le_mono.
+ destruct (lt_trichotomy b 1) as [Hb'|[Hb'|Hb']]; [|order|].
+ rewrite one_succ, lt_succ_r in Hb'.
+ rewrite (log2_nonpos b); trivial. nzsimpl. apply log2_le_mono.
+ rewrite <- (add_0_r a) at 2. now apply add_le_mono.
+ clear Ha Hb.
+ apply lt_succ_r.
+ apply log2_lt_pow2; try order_pos.
+ rewrite pow_succ_r by order_pos.
+ rewrite two_succ, one_succ at 1. nzsimpl.
+ apply add_lt_mono.
+ apply lt_le_trans with (2^(S (log2 a))). apply log2_spec; order'.
+ apply pow_le_mono_r. order'. rewrite <- add_1_r. apply add_le_mono_l.
+ rewrite one_succ; now apply le_succ_l, log2_pos.
+ apply lt_le_trans with (2^(S (log2 b))). apply log2_spec; order'.
+ apply pow_le_mono_r. order'. rewrite <- add_1_l. apply add_le_mono_r.
+ rewrite one_succ; now apply le_succ_l, log2_pos.
+Qed.
+
+(** The sum of two log2 is less than twice the log2 of the sum.
+ The large inequality is obvious thanks to monotonicity.
+ The strict one requires some more work. This is almost
+ a convexity inequality for points [2a], [2b] and their middle [a+b] :
+ ideally, we would have [2*log(a+b) >= log(2a)+log(2b) = 2+log a+log b].
+ Here, we cannot do better: consider for instance a=2 b=4, then 1+2<2*2
+*)
+
+Lemma add_log2_lt : forall a b, 0<a -> 0<b ->
+ log2 a + log2 b < 2 * log2 (a+b).
+Proof.
+ intros a b Ha Hb. nzsimpl'.
+ assert (H : log2 a <= log2 (a+b)).
+ apply log2_le_mono. rewrite <- (add_0_r a) at 1. apply add_le_mono; order.
+ assert (H' : log2 b <= log2 (a+b)).
+ apply log2_le_mono. rewrite <- (add_0_l b) at 1. apply add_le_mono; order.
+ le_elim H.
+ apply lt_le_trans with (log2 (a+b) + log2 b).
+ now apply add_lt_mono_r. now apply add_le_mono_l.
+ rewrite <- H at 1. apply add_lt_mono_l.
+ le_elim H'; trivial.
+ symmetry in H. apply log2_same in H; try order_pos.
+ symmetry in H'. apply log2_same in H'; try order_pos.
+ revert H H'. nzsimpl'. rewrite <- add_lt_mono_l, <- add_lt_mono_r; order.
+Qed.
+
+End NZLog2Prop.
+
+Module NZLog2UpProp
+ (Import A : NZDecOrdAxiomsSig')
+ (Import B : NZPow' A)
+ (Import C : NZLog2 A B)
+ (Import D : NZMulOrderProp A)
+ (Import E : NZPowProp A B D)
+ (Import F : NZLog2Prop A B C D E).
+
+(** * [log2_up] : a binary logarithm that rounds up instead of down *)
+
+(** For once, we define instead of axiomatizing, thanks to log2 *)
+
+Definition log2_up a :=
+ match compare 1 a with
+ | Lt => S (log2 (P a))
+ | _ => 0
+ end.
+
+Lemma log2_up_eqn0 : forall a, a<=1 -> log2_up a == 0.
+Proof.
+ intros a Ha. unfold log2_up. case compare_spec; try order.
+Qed.
+
+Lemma log2_up_eqn : forall a, 1<a -> log2_up a == S (log2 (P a)).
+Proof.
+ intros a Ha. unfold log2_up. case compare_spec; try order.
+Qed.
+
+Lemma log2_up_spec : forall a, 1<a ->
+ 2^(P (log2_up a)) < a <= 2^(log2_up a).
+Proof.
+ intros a Ha.
+ rewrite log2_up_eqn; trivial.
+ rewrite pred_succ.
+ rewrite <- (lt_succ_pred 1 a Ha) at 2 3.
+ rewrite lt_succ_r, le_succ_l.
+ apply log2_spec.
+ apply succ_lt_mono. now rewrite (lt_succ_pred 1 a Ha), <- one_succ.
+Qed.
+
+Lemma log2_up_nonpos : forall a, a<=0 -> log2_up a == 0.
+Proof.
+ intros. apply log2_up_eqn0. order'.
+Qed.
+
+Instance log2_up_wd : Proper (eq==>eq) log2_up.
+Proof.
+ assert (Proper (eq==>eq==>Logic.eq) compare).
+ repeat red; intros; do 2 case compare_spec; trivial; order.
+ intros a a' Ha. unfold log2_up. rewrite Ha at 1.
+ case compare; now rewrite ?Ha.
+Qed.
+
+(** [log2_up] is always non-negative *)
+
+Lemma log2_up_nonneg : forall a, 0 <= log2_up a.
+Proof.
+ intros a. unfold log2_up. case compare_spec; try order.
+ intros. apply le_le_succ_r, log2_nonneg.
+Qed.
+
+(** The spec of [log2_up] indeed determines it *)
+
+Lemma log2_up_unique : forall a b, 0<b -> 2^(P b)<a<=2^b -> log2_up a == b.
+Proof.
+ intros a b Hb (LEb,LTb).
+ assert (Ha : 1 < a).
+ apply le_lt_trans with (2^(P b)); trivial.
+ rewrite one_succ. apply le_succ_l.
+ apply pow_pos_nonneg. order'. apply lt_succ_r.
+ now rewrite (lt_succ_pred 0 b Hb).
+ assert (Hc := log2_up_nonneg a).
+ destruct (log2_up_spec a Ha) as (LTc,LEc).
+ assert (b <= log2_up a).
+ apply lt_succ_r. rewrite <- (lt_succ_pred 0 b Hb).
+ rewrite <- succ_lt_mono.
+ apply (pow_lt_mono_r_iff 2); try order'.
+ assert (Hc' : 0 < log2_up a) by order.
+ assert (log2_up a <= b).
+ apply lt_succ_r. rewrite <- (lt_succ_pred 0 _ Hc').
+ rewrite <- succ_lt_mono.
+ apply (pow_lt_mono_r_iff 2); try order'.
+ order.
+Qed.
+
+(** [log2_up] is exact on powers of 2 *)
+
+Lemma log2_up_pow2 : forall a, 0<=a -> log2_up (2^a) == a.
+Proof.
+ intros a Ha.
+ le_elim Ha.
+ apply log2_up_unique; trivial.
+ split; try order.
+ apply pow_lt_mono_r; try order'.
+ rewrite <- (lt_succ_pred 0 a Ha) at 2.
+ now apply lt_succ_r.
+ now rewrite <- Ha, pow_0_r, log2_up_eqn0.
+Qed.
+
+(** [log2_up] and successors of powers of 2 *)
+
+Lemma log2_up_succ_pow2 : forall a, 0<=a -> log2_up (S (2^a)) == S a.
+Proof.
+ intros a Ha.
+ rewrite log2_up_eqn, pred_succ, log2_pow2; try easy.
+ rewrite one_succ, <- succ_lt_mono. apply pow_pos_nonneg; order'.
+Qed.
+
+(** Basic constants *)
+
+Lemma log2_up_1 : log2_up 1 == 0.
+Proof.
+ now apply log2_up_eqn0.
+Qed.
+
+Lemma log2_up_2 : log2_up 2 == 1.
+Proof.
+ rewrite <- (pow_1_r 2). apply log2_up_pow2; order'.
+Qed.
+
+(** Links between log2 and [log2_up] *)
+
+Lemma le_log2_log2_up : forall a, log2 a <= log2_up a.
+Proof.
+ intros a. unfold log2_up. case compare_spec; intros H.
+ rewrite <- H, log2_1. order.
+ rewrite <- (lt_succ_pred 1 a H) at 1. apply log2_succ_le.
+ rewrite log2_nonpos. order. now rewrite <-lt_succ_r, <-one_succ.
+Qed.
+
+Lemma le_log2_up_succ_log2 : forall a, log2_up a <= S (log2 a).
+Proof.
+ intros a. unfold log2_up. case compare_spec; intros H; try order_pos.
+ rewrite <- succ_le_mono. apply log2_le_mono.
+ rewrite <- (lt_succ_pred 1 a H) at 2. apply le_succ_diag_r.
+Qed.
+
+Lemma log2_log2_up_spec : forall a, 0<a ->
+ 2^log2 a <= a <= 2^log2_up a.
+Proof.
+ intros a H. split.
+ now apply log2_spec.
+ rewrite <-le_succ_l, <-one_succ in H. le_elim H.
+ now apply log2_up_spec.
+ now rewrite <-H, log2_up_1, pow_0_r.
+Qed.
+
+Lemma log2_log2_up_exact :
+ forall a, 0<a -> (log2 a == log2_up a <-> exists b, a == 2^b).
+Proof.
+ intros a Ha.
+ split. intros. exists (log2 a).
+ generalize (log2_log2_up_spec a Ha). rewrite <-H.
+ destruct 1; order.
+ intros (b,Hb). rewrite Hb.
+ destruct (le_gt_cases 0 b).
+ now rewrite log2_pow2, log2_up_pow2.
+ rewrite pow_neg_r; trivial. now rewrite log2_nonpos, log2_up_nonpos.
+Qed.
+
+(** [log2_up] n is strictly positive for 1<n *)
+
+Lemma log2_up_pos : forall a, 1<a -> 0 < log2_up a.
+Proof.
+ intros. rewrite log2_up_eqn; trivial. apply lt_succ_r; order_pos.
+Qed.
+
+(** Said otherwise, [log2_up] is null only below 1 *)
+
+Lemma log2_up_null : forall a, log2_up a == 0 <-> a <= 1.
+Proof.
+ intros a. split; intros H.
+ destruct (le_gt_cases a 1) as [Ha|Ha]; trivial.
+ generalize (log2_up_pos a Ha); order.
+ now apply log2_up_eqn0.
+Qed.
+
+(** [log2_up] is a monotone function (but not a strict one) *)
+
+Lemma log2_up_le_mono : forall a b, a<=b -> log2_up a <= log2_up b.
+Proof.
+ intros a b H.
+ destruct (le_gt_cases a 1) as [Ha|Ha].
+ rewrite log2_up_eqn0; trivial. apply log2_up_nonneg.
+ rewrite 2 log2_up_eqn; try order.
+ rewrite <- succ_le_mono. apply log2_le_mono, succ_le_mono.
+ rewrite 2 lt_succ_pred with 1; order.
+Qed.
+
+(** No reverse result for <=, consider for instance log2_up 4 <= log2_up 3 *)
+
+Lemma log2_up_lt_cancel : forall a b, log2_up a < log2_up b -> a < b.
+Proof.
+ intros a b H.
+ destruct (le_gt_cases b 1) as [Hb|Hb].
+ rewrite (log2_up_eqn0 b) in H; trivial.
+ generalize (log2_up_nonneg a); order.
+ destruct (le_gt_cases a 1) as [Ha|Ha]. order.
+ rewrite 2 log2_up_eqn in H; try order.
+ rewrite <- succ_lt_mono in H. apply log2_lt_cancel, succ_lt_mono in H.
+ rewrite 2 lt_succ_pred with 1 in H; order.
+Qed.
+
+(** When left side is a power of 2, we have an equivalence for < *)
+
+Lemma log2_up_lt_pow2 : forall a b, 0<a -> (2^b<a <-> b < log2_up a).
+Proof.
+ intros a b Ha.
+ split; intros H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ generalize (log2_up_nonneg a); order.
+ apply (pow_lt_mono_r_iff 2). order'. apply log2_up_nonneg.
+ apply lt_le_trans with a; trivial.
+ apply (log2_up_spec a).
+ apply le_lt_trans with (2^b); trivial.
+ rewrite one_succ, le_succ_l. apply pow_pos_nonneg; order'.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ now rewrite pow_neg_r.
+ rewrite <- (log2_up_pow2 b) in H; trivial. now apply log2_up_lt_cancel.
+Qed.
+
+(** When right side is a square, we have an equivalence for <= *)
+
+Lemma log2_up_le_pow2 : forall a b, 0<a -> (a<=2^b <-> log2_up a <= b).
+Proof.
+ intros a b Ha.
+ split; intros H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite pow_neg_r in H; order.
+ rewrite <- (log2_up_pow2 b); trivial. now apply log2_up_le_mono.
+ transitivity (2^(log2_up a)).
+ now apply log2_log2_up_spec.
+ apply pow_le_mono_r; order'.
+Qed.
+
+(** Comparing [log2_up] and identity *)
+
+Lemma log2_up_lt_lin : forall a, 0<a -> log2_up a < a.
+Proof.
+ intros a Ha.
+ assert (H : S (P a) == a) by (now apply lt_succ_pred with 0).
+ rewrite <- H at 2. apply lt_succ_r. apply log2_up_le_pow2; trivial.
+ rewrite <- H at 1. apply le_succ_l.
+ apply pow_gt_lin_r. order'. apply lt_succ_r; order.
+Qed.
+
+Lemma log2_up_le_lin : forall a, 0<=a -> log2_up a <= a.
+Proof.
+ intros a Ha.
+ le_elim Ha.
+ now apply lt_le_incl, log2_up_lt_lin.
+ rewrite <- Ha, log2_up_nonpos; order.
+Qed.
+
+(** [log2_up] and multiplication. *)
+
+(** Due to rounding error, we don't have the usual
+ [log2_up (a*b) = log2_up a + log2_up b] but we may be off by 1 at most *)
+
+Lemma log2_up_mul_above : forall a b, 0<=a -> 0<=b ->
+ log2_up (a*b) <= log2_up a + log2_up b.
+Proof.
+ intros a b Ha Hb.
+ assert (Ha':=log2_up_nonneg a).
+ assert (Hb':=log2_up_nonneg b).
+ le_elim Ha.
+ le_elim Hb.
+ apply log2_up_le_pow2; try order_pos.
+ rewrite pow_add_r; trivial.
+ apply mul_le_mono_nonneg; try apply log2_log2_up_spec; order'.
+ rewrite <- Hb. nzsimpl. rewrite log2_up_nonpos; order_pos.
+ rewrite <- Ha. nzsimpl. rewrite log2_up_nonpos; order_pos.
+Qed.
+
+Lemma log2_up_mul_below : forall a b, 0<a -> 0<b ->
+ log2_up a + log2_up b <= S (log2_up (a*b)).
+Proof.
+ intros a b Ha Hb.
+ rewrite <-le_succ_l, <-one_succ in Ha. le_elim Ha.
+ rewrite <-le_succ_l, <-one_succ in Hb. le_elim Hb.
+ assert (Ha' : 0 < log2_up a) by (apply log2_up_pos; trivial).
+ assert (Hb' : 0 < log2_up b) by (apply log2_up_pos; trivial).
+ rewrite <- (lt_succ_pred 0 (log2_up a)); trivial.
+ rewrite <- (lt_succ_pred 0 (log2_up b)); trivial.
+ nzsimpl. rewrite <- succ_le_mono, le_succ_l.
+ apply (pow_lt_mono_r_iff 2). order'. apply log2_up_nonneg.
+ rewrite pow_add_r; try (apply lt_succ_r; rewrite (lt_succ_pred 0); trivial).
+ apply lt_le_trans with (a*b).
+ apply mul_lt_mono_nonneg; try order_pos; try now apply log2_up_spec.
+ apply log2_up_spec.
+ setoid_replace 1 with (1*1) by now nzsimpl.
+ apply mul_lt_mono_nonneg; order'.
+ rewrite <- Hb, log2_up_1; nzsimpl. apply le_succ_diag_r.
+ rewrite <- Ha, log2_up_1; nzsimpl. apply le_succ_diag_r.
+Qed.
+
+(** And we can't find better approximations in general.
+ - The upper bound is exact for powers of 2.
+ - Concerning the lower bound, for any c>1, take a=b=2^c+1,
+ then [log2_up (a*b) = c+c +1] while [(log2_up a) = (log2_up b) = c+1]
+*)
+
+(** At least, we get back the usual equation when we multiply by 2 (or 2^k) *)
+
+Lemma log2_up_mul_pow2 : forall a b, 0<a -> 0<=b ->
+ log2_up (a*2^b) == b + log2_up a.
+Proof.
+ intros a b Ha Hb.
+ rewrite <- le_succ_l, <- one_succ in Ha; le_elim Ha.
+ apply log2_up_unique. apply add_nonneg_pos; trivial. now apply log2_up_pos.
+ split.
+ assert (EQ := lt_succ_pred 0 _ (log2_up_pos _ Ha)).
+ rewrite <- EQ. nzsimpl. rewrite pow_add_r, mul_comm; trivial.
+ apply mul_lt_mono_pos_r. order_pos. now apply log2_up_spec.
+ rewrite <- lt_succ_r, EQ. now apply log2_up_pos.
+ rewrite pow_add_r, mul_comm; trivial.
+ apply mul_le_mono_nonneg_l. order_pos. now apply log2_up_spec.
+ apply log2_up_nonneg.
+ now rewrite <- Ha, mul_1_l, log2_up_1, add_0_r, log2_up_pow2.
+Qed.
+
+Lemma log2_up_double : forall a, 0<a -> log2_up (2*a) == S (log2_up a).
+Proof.
+ intros a Ha. generalize (log2_up_mul_pow2 a 1 Ha le_0_1). now nzsimpl'.
+Qed.
+
+(** Two numbers with same [log2_up] cannot be far away. *)
+
+Lemma log2_up_same : forall a b, 0<a -> 0<b -> log2_up a == log2_up b -> a < 2*b.
+Proof.
+ intros a b Ha Hb H.
+ apply log2_up_lt_cancel. rewrite log2_up_double, H by trivial.
+ apply lt_succ_diag_r.
+Qed.
+
+(** [log2_up] and successor :
+ - the [log2_up] function climbs by at most 1 at a time
+ - otherwise it stays at the same value
+ - the +1 steps occur after powers of two
+*)
+
+Lemma log2_up_succ_le : forall a, log2_up (S a) <= S (log2_up a).
+Proof.
+ intros a.
+ destruct (lt_trichotomy 1 a) as [LT|[EQ|LT]].
+ rewrite 2 log2_up_eqn; trivial.
+ rewrite pred_succ, <- succ_le_mono. rewrite <-(lt_succ_pred 1 a LT) at 1.
+ apply log2_succ_le.
+ apply lt_succ_r; order.
+ rewrite <- EQ, <- two_succ, log2_up_1, log2_up_2. now nzsimpl'.
+ rewrite 2 log2_up_eqn0. order_pos. order'. now rewrite le_succ_l.
+Qed.
+
+Lemma log2_up_succ_or : forall a,
+ log2_up (S a) == S (log2_up a) \/ log2_up (S a) == log2_up a.
+Proof.
+ intros.
+ destruct (le_gt_cases (log2_up (S a)) (log2_up a)).
+ right. generalize (log2_up_le_mono _ _ (le_succ_diag_r a)); order.
+ left. apply le_succ_l in H. generalize (log2_up_succ_le a); order.
+Qed.
+
+Lemma log2_up_eq_succ_is_pow2 : forall a,
+ log2_up (S a) == S (log2_up a) -> exists b, a == 2^b.
+Proof.
+ intros a H.
+ destruct (le_gt_cases a 0) as [Ha|Ha].
+ rewrite 2 (proj2 (log2_up_null _)) in H. generalize (lt_succ_diag_r 0); order.
+ order'. apply le_succ_l. order'.
+ assert (Ha' : 1 < S a) by (now rewrite one_succ, <- succ_lt_mono).
+ exists (log2_up a).
+ generalize (proj1 (log2_up_spec (S a) Ha')) (proj2 (log2_log2_up_spec a Ha)).
+ rewrite H, pred_succ, lt_succ_r. order.
+Qed.
+
+Lemma log2_up_eq_succ_iff_pow2 : forall a, 0<a ->
+ (log2_up (S a) == S (log2_up a) <-> exists b, a == 2^b).
+Proof.
+ intros a Ha.
+ split. apply log2_up_eq_succ_is_pow2.
+ intros (b,Hb).
+ destruct (lt_ge_cases b 0) as [Hb'|Hb'].
+ rewrite pow_neg_r in Hb; order.
+ rewrite Hb, log2_up_pow2; try order'.
+ now rewrite log2_up_succ_pow2.
+Qed.
+
+Lemma log2_up_succ_double : forall a, 0<a ->
+ log2_up (2*a+1) == 2 + log2 a.
+Proof.
+ intros a Ha.
+ rewrite log2_up_eqn. rewrite add_1_r, pred_succ, log2_double; now nzsimpl'.
+ apply le_lt_trans with (0+1). now nzsimpl'.
+ apply add_lt_mono_r. order_pos.
+Qed.
+
+(** [log2_up] and addition *)
+
+Lemma log2_up_add_le : forall a b, a~=1 -> b~=1 ->
+ log2_up (a+b) <= log2_up a + log2_up b.
+Proof.
+ intros a b Ha Hb.
+ destruct (lt_trichotomy a 1) as [Ha'|[Ha'|Ha']]; [|order|].
+ rewrite (log2_up_eqn0 a) by order. nzsimpl. apply log2_up_le_mono.
+ rewrite one_succ, lt_succ_r in Ha'.
+ rewrite <- (add_0_l b) at 2. now apply add_le_mono.
+ destruct (lt_trichotomy b 1) as [Hb'|[Hb'|Hb']]; [|order|].
+ rewrite (log2_up_eqn0 b) by order. nzsimpl. apply log2_up_le_mono.
+ rewrite one_succ, lt_succ_r in Hb'.
+ rewrite <- (add_0_r a) at 2. now apply add_le_mono.
+ clear Ha Hb.
+ transitivity (log2_up (a*b)).
+ now apply log2_up_le_mono, add_le_mul.
+ apply log2_up_mul_above; order'.
+Qed.
+
+(** The sum of two [log2_up] is less than twice the [log2_up] of the sum.
+ The large inequality is obvious thanks to monotonicity.
+ The strict one requires some more work. This is almost
+ a convexity inequality for points [2a], [2b] and their middle [a+b] :
+ ideally, we would have [2*log(a+b) >= log(2a)+log(2b) = 2+log a+log b].
+ Here, we cannot do better: consider for instance a=3 b=5, then 2+3<2*3
+*)
+
+Lemma add_log2_up_lt : forall a b, 0<a -> 0<b ->
+ log2_up a + log2_up b < 2 * log2_up (a+b).
+Proof.
+ intros a b Ha Hb. nzsimpl'.
+ assert (H : log2_up a <= log2_up (a+b)).
+ apply log2_up_le_mono. rewrite <- (add_0_r a) at 1. apply add_le_mono; order.
+ assert (H' : log2_up b <= log2_up (a+b)).
+ apply log2_up_le_mono. rewrite <- (add_0_l b) at 1. apply add_le_mono; order.
+ le_elim H.
+ apply lt_le_trans with (log2_up (a+b) + log2_up b).
+ now apply add_lt_mono_r. now apply add_le_mono_l.
+ rewrite <- H at 1. apply add_lt_mono_l.
+ le_elim H'. trivial.
+ symmetry in H. apply log2_up_same in H; try order_pos.
+ symmetry in H'. apply log2_up_same in H'; try order_pos.
+ revert H H'. nzsimpl'. rewrite <- add_lt_mono_l, <- add_lt_mono_r; order.
+Qed.
+
+End NZLog2UpProp.
+
diff --git a/theories/Numbers/NatInt/NZMul.v b/theories/Numbers/NatInt/NZMul.v
index b1adcea9..2b5a1cf3 100644
--- a/theories/Numbers/NatInt/NZMul.v
+++ b/theories/Numbers/NatInt/NZMul.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,13 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZMul.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NZAxioms NZBase NZAdd.
-Module Type NZMulPropSig
- (Import NZ : NZAxiomsSig')(Import NZBase : NZBasePropSig NZ).
-Include NZAddPropSig NZ NZBase.
+Module Type NZMulProp (Import NZ : NZAxiomsSig')(Import NZBase : NZBaseProp NZ).
+Include NZAddProp NZ NZBase.
Theorem mul_0_r : forall n, n * 0 == 0.
Proof.
@@ -59,12 +56,34 @@ Qed.
Theorem mul_1_l : forall n, 1 * n == n.
Proof.
-intro n. now nzsimpl.
+intro n. now nzsimpl'.
Qed.
Theorem mul_1_r : forall n, n * 1 == n.
Proof.
-intro n. now nzsimpl.
+intro n. now nzsimpl'.
+Qed.
+
+Hint Rewrite mul_1_l mul_1_r : nz.
+
+Theorem mul_shuffle0 : forall n m p, n*m*p == n*p*m.
+Proof.
+intros n m p. now rewrite <- 2 mul_assoc, (mul_comm m).
+Qed.
+
+Theorem mul_shuffle1 : forall n m p q, (n * m) * (p * q) == (n * p) * (m * q).
+Proof.
+intros n m p q. now rewrite 2 mul_assoc, (mul_shuffle0 n).
+Qed.
+
+Theorem mul_shuffle2 : forall n m p q, (n * m) * (p * q) == (n * q) * (m * p).
+Proof.
+intros n m p q. rewrite (mul_comm p). apply mul_shuffle1.
+Qed.
+
+Theorem mul_shuffle3 : forall n m p, n * (m * p) == m * (n * p).
+Proof.
+intros n m p. now rewrite mul_assoc, (mul_comm n), mul_assoc.
Qed.
-End NZMulPropSig.
+End NZMulProp.
diff --git a/theories/Numbers/NatInt/NZMulOrder.v b/theories/Numbers/NatInt/NZMulOrder.v
index 09e468ff..97306f93 100644
--- a/theories/Numbers/NatInt/NZMulOrder.v
+++ b/theories/Numbers/NatInt/NZMulOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,13 +8,11 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZMulOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NZAxioms.
Require Import NZAddOrder.
-Module Type NZMulOrderPropSig (Import NZ : NZOrdAxiomsSig').
-Include NZAddOrderPropSig NZ.
+Module Type NZMulOrderProp (Import NZ : NZOrdAxiomsSig').
+Include NZAddOrderProp NZ.
Theorem mul_lt_pred :
forall p q n m, S p == q -> (p * n < p * m <-> q * n + m < q * m + n).
@@ -26,17 +24,16 @@ Qed.
Theorem mul_lt_mono_pos_l : forall p n m, 0 < p -> (n < m <-> p * n < p * m).
Proof.
-nzord_induct p.
-intros n m H; false_hyp H lt_irrefl.
-intros p H IH n m H1. nzsimpl.
-le_elim H. assert (LR : forall n m, n < m -> p * n + n < p * m + m).
-intros n1 m1 H2. apply add_lt_mono; [now apply -> IH | assumption].
-split; [apply LR |]. intro H2. apply -> lt_dne; intro H3.
-apply <- le_ngt in H3. le_elim H3.
-apply lt_asymm in H2. apply H2. now apply LR.
-rewrite H3 in H2; false_hyp H2 lt_irrefl.
-rewrite <- H; now nzsimpl.
-intros p H1 _ n m H2. destruct (lt_asymm _ _ H1 H2).
+intros p n m Hp. revert n m. apply lt_ind with (4:=Hp). solve_proper.
+intros. now nzsimpl.
+clear p Hp. intros p Hp IH n m. nzsimpl.
+assert (LR : forall n m, n < m -> p * n + n < p * m + m)
+ by (intros n1 m1 H; apply add_lt_mono; trivial; now rewrite <- IH).
+split; intros H.
+now apply LR.
+destruct (lt_trichotomy n m) as [LT|[EQ|GT]]; trivial.
+rewrite EQ in H. order.
+apply LR in GT. order.
Qed.
Theorem mul_lt_mono_pos_r : forall p n m, 0 < p -> (n < m <-> n * p < m * p).
@@ -48,19 +45,19 @@ Qed.
Theorem mul_lt_mono_neg_l : forall p n m, p < 0 -> (n < m <-> p * m < p * n).
Proof.
nzord_induct p.
-intros n m H; false_hyp H lt_irrefl.
-intros p H1 _ n m H2. apply lt_succ_l in H2. apply <- nle_gt in H2.
-false_hyp H1 H2.
-intros p H IH n m H1. apply <- le_succ_l in H.
-le_elim H. assert (LR : forall n m, n < m -> p * m < p * n).
-intros n1 m1 H2. apply (le_lt_add_lt n1 m1).
-now apply lt_le_incl. rewrite <- 2 mul_succ_l. now apply -> IH.
-split; [apply LR |]. intro H2. apply -> lt_dne; intro H3.
-apply <- le_ngt in H3. le_elim H3.
-apply lt_asymm in H2. apply H2. now apply LR.
-rewrite H3 in H2; false_hyp H2 lt_irrefl.
-rewrite (mul_lt_pred p (S p)) by reflexivity.
-rewrite H; do 2 rewrite mul_0_l; now do 2 rewrite add_0_l.
+order.
+intros p Hp _ n m Hp'. apply lt_succ_l in Hp'. order.
+intros p Hp IH n m _. apply le_succ_l in Hp.
+le_elim Hp.
+assert (LR : forall n m, n < m -> p * m < p * n).
+ intros n1 m1 H. apply (le_lt_add_lt n1 m1).
+ now apply lt_le_incl. rewrite <- 2 mul_succ_l. now rewrite <- IH.
+split; intros H.
+now apply LR.
+destruct (lt_trichotomy n m) as [LT|[EQ|GT]]; trivial.
+rewrite EQ in H. order.
+apply LR in GT. order.
+rewrite (mul_lt_pred p (S p)), Hp; now nzsimpl.
Qed.
Theorem mul_lt_mono_neg_r : forall p n m, p < 0 -> (n < m <-> m * p < n * p).
@@ -72,7 +69,7 @@ Qed.
Theorem mul_le_mono_nonneg_l : forall n m p, 0 <= p -> n <= m -> p * n <= p * m.
Proof.
intros n m p H1 H2. le_elim H1.
-le_elim H2. apply lt_le_incl. now apply -> mul_lt_mono_pos_l.
+le_elim H2. apply lt_le_incl. now apply mul_lt_mono_pos_l.
apply eq_le_incl; now rewrite H2.
apply eq_le_incl; rewrite <- H1; now do 2 rewrite mul_0_l.
Qed.
@@ -80,7 +77,7 @@ Qed.
Theorem mul_le_mono_nonpos_l : forall n m p, p <= 0 -> n <= m -> p * m <= p * n.
Proof.
intros n m p H1 H2. le_elim H1.
-le_elim H2. apply lt_le_incl. now apply -> mul_lt_mono_neg_l.
+le_elim H2. apply lt_le_incl. now apply mul_lt_mono_neg_l.
apply eq_le_incl; now rewrite H2.
apply eq_le_incl; rewrite H1; now do 2 rewrite mul_0_l.
Qed.
@@ -99,20 +96,13 @@ Qed.
Theorem mul_cancel_l : forall n m p, p ~= 0 -> (p * n == p * m <-> n == m).
Proof.
-intros n m p H; split; intro H1.
-destruct (lt_trichotomy p 0) as [H2 | [H2 | H2]].
-apply -> eq_dne; intro H3. apply -> lt_gt_cases in H3. destruct H3 as [H3 | H3].
-assert (H4 : p * m < p * n); [now apply -> mul_lt_mono_neg_l |].
-rewrite H1 in H4; false_hyp H4 lt_irrefl.
-assert (H4 : p * n < p * m); [now apply -> mul_lt_mono_neg_l |].
-rewrite H1 in H4; false_hyp H4 lt_irrefl.
-false_hyp H2 H.
-apply -> eq_dne; intro H3. apply -> lt_gt_cases in H3. destruct H3 as [H3 | H3].
-assert (H4 : p * n < p * m) by (now apply -> mul_lt_mono_pos_l).
-rewrite H1 in H4; false_hyp H4 lt_irrefl.
-assert (H4 : p * m < p * n) by (now apply -> mul_lt_mono_pos_l).
-rewrite H1 in H4; false_hyp H4 lt_irrefl.
-now rewrite H1.
+intros n m p Hp; split; intro H; [|now f_equiv].
+apply lt_gt_cases in Hp; destruct Hp as [Hp|Hp];
+ destruct (lt_trichotomy n m) as [LT|[EQ|GT]]; trivial.
+apply (mul_lt_mono_neg_l p) in LT; order.
+apply (mul_lt_mono_neg_l p) in GT; order.
+apply (mul_lt_mono_pos_l p) in LT; order.
+apply (mul_lt_mono_pos_l p) in GT; order.
Qed.
Theorem mul_cancel_r : forall n m p, p ~= 0 -> (n * p == m * p <-> n == m).
@@ -183,17 +173,17 @@ Qed.
Theorem mul_pos_pos : forall n m, 0 < n -> 0 < m -> 0 < n * m.
Proof.
-intros n m H1 H2. rewrite <- (mul_0_l m). now apply -> mul_lt_mono_pos_r.
+intros n m H1 H2. rewrite <- (mul_0_l m). now apply mul_lt_mono_pos_r.
Qed.
Theorem mul_neg_neg : forall n m, n < 0 -> m < 0 -> 0 < n * m.
Proof.
-intros n m H1 H2. rewrite <- (mul_0_l m). now apply -> mul_lt_mono_neg_r.
+intros n m H1 H2. rewrite <- (mul_0_l m). now apply mul_lt_mono_neg_r.
Qed.
Theorem mul_pos_neg : forall n m, 0 < n -> m < 0 -> n * m < 0.
Proof.
-intros n m H1 H2. rewrite <- (mul_0_l m). now apply -> mul_lt_mono_neg_r.
+intros n m H1 H2. rewrite <- (mul_0_l m). now apply mul_lt_mono_neg_r.
Qed.
Theorem mul_neg_pos : forall n m, n < 0 -> 0 < m -> n * m < 0.
@@ -206,9 +196,33 @@ Proof.
intros. rewrite <- (mul_0_l m). apply mul_le_mono_nonneg; order.
Qed.
+Theorem mul_pos_cancel_l : forall n m, 0 < n -> (0 < n*m <-> 0 < m).
+Proof.
+intros n m Hn. rewrite <- (mul_0_r n) at 1.
+ symmetry. now apply mul_lt_mono_pos_l.
+Qed.
+
+Theorem mul_pos_cancel_r : forall n m, 0 < m -> (0 < n*m <-> 0 < n).
+Proof.
+intros n m Hn. rewrite <- (mul_0_l m) at 1.
+ symmetry. now apply mul_lt_mono_pos_r.
+Qed.
+
+Theorem mul_nonneg_cancel_l : forall n m, 0 < n -> (0 <= n*m <-> 0 <= m).
+Proof.
+intros n m Hn. rewrite <- (mul_0_r n) at 1.
+ symmetry. now apply mul_le_mono_pos_l.
+Qed.
+
+Theorem mul_nonneg_cancel_r : forall n m, 0 < m -> (0 <= n*m <-> 0 <= n).
+Proof.
+intros n m Hn. rewrite <- (mul_0_l m) at 1.
+ symmetry. now apply mul_le_mono_pos_r.
+Qed.
+
Theorem lt_1_mul_pos : forall n m, 1 < n -> 0 < m -> 1 < n * m.
Proof.
-intros n m H1 H2. apply -> (mul_lt_mono_pos_r m) in H1.
+intros n m H1 H2. apply (mul_lt_mono_pos_r m) in H1.
rewrite mul_1_l in H1. now apply lt_1_l with m.
assumption.
Qed.
@@ -229,7 +243,7 @@ Qed.
Theorem neq_mul_0 : forall n m, n ~= 0 /\ m ~= 0 <-> n * m ~= 0.
Proof.
intros n m; split; intro H.
-intro H1; apply -> eq_mul_0 in H1. tauto.
+intro H1; apply eq_mul_0 in H1. tauto.
split; intro H1; rewrite H1 in H;
(rewrite mul_0_l in H || rewrite mul_0_r in H); now apply H.
Qed.
@@ -241,16 +255,22 @@ Qed.
Theorem eq_mul_0_l : forall n m, n * m == 0 -> m ~= 0 -> n == 0.
Proof.
-intros n m H1 H2. apply -> eq_mul_0 in H1. destruct H1 as [H1 | H1].
+intros n m H1 H2. apply eq_mul_0 in H1. destruct H1 as [H1 | H1].
assumption. false_hyp H1 H2.
Qed.
Theorem eq_mul_0_r : forall n m, n * m == 0 -> n ~= 0 -> m == 0.
Proof.
-intros n m H1 H2; apply -> eq_mul_0 in H1. destruct H1 as [H1 | H1].
+intros n m H1 H2; apply eq_mul_0 in H1. destruct H1 as [H1 | H1].
false_hyp H1 H2. assumption.
Qed.
+(** Some alternative names: *)
+
+Definition mul_eq_0 := eq_mul_0.
+Definition mul_eq_0_l := eq_mul_0_l.
+Definition mul_eq_0_r := eq_mul_0_r.
+
Theorem lt_0_mul : forall n m, 0 < n * m <-> (0 < n /\ 0 < m) \/ (m < 0 /\ n < 0).
Proof.
intros n m; split; [intro H | intros [[H1 H2] | [H1 H2]]].
@@ -283,25 +303,100 @@ Theorem square_lt_simpl_nonneg : forall n m, 0 <= m -> n * n < m * m -> n < m.
Proof.
intros n m H1 H2. destruct (lt_ge_cases n 0).
now apply lt_le_trans with 0.
-destruct (lt_ge_cases n m).
-assumption. assert (F : m * m <= n * n) by now apply square_le_mono_nonneg.
-apply -> le_ngt in F. false_hyp H2 F.
+destruct (lt_ge_cases n m) as [LT|LE]; trivial.
+apply square_le_mono_nonneg in LE; order.
Qed.
Theorem square_le_simpl_nonneg : forall n m, 0 <= m -> n * n <= m * m -> n <= m.
Proof.
intros n m H1 H2. destruct (lt_ge_cases n 0).
apply lt_le_incl; now apply lt_le_trans with 0.
-destruct (le_gt_cases n m).
-assumption. assert (F : m * m < n * n) by now apply square_lt_mono_nonneg.
-apply -> lt_nge in F. false_hyp H2 F.
+destruct (le_gt_cases n m) as [LE|LT]; trivial.
+apply square_lt_mono_nonneg in LT; order.
+Qed.
+
+Theorem mul_2_mono_l : forall n m, n < m -> 1 + 2 * n < 2 * m.
+Proof.
+intros n m. rewrite <- le_succ_l, (mul_le_mono_pos_l (S n) m two).
+rewrite two_succ. nzsimpl. now rewrite le_succ_l.
+order'.
+Qed.
+
+Lemma add_le_mul : forall a b, 1<a -> 1<b -> a+b <= a*b.
+Proof.
+ assert (AUX : forall a b, 0<a -> 0<b -> (S a)+(S b) <= (S a)*(S b)).
+ intros a b Ha Hb.
+ nzsimpl. rewrite <- succ_le_mono. apply le_succ_l.
+ rewrite <- add_assoc, <- (add_0_l (a+b)), (add_comm b).
+ apply add_lt_mono_r.
+ now apply mul_pos_pos.
+ intros a b Ha Hb.
+ assert (Ha' := lt_succ_pred 1 a Ha).
+ assert (Hb' := lt_succ_pred 1 b Hb).
+ rewrite <- Ha', <- Hb'. apply AUX; rewrite succ_lt_mono, <- one_succ; order.
+Qed.
+
+(** A few results about squares *)
+
+Lemma square_nonneg : forall a, 0 <= a * a.
+Proof.
+ intros. rewrite <- (mul_0_r a). destruct (le_gt_cases a 0).
+ now apply mul_le_mono_nonpos_l.
+ apply mul_le_mono_nonneg_l; order.
+Qed.
+
+Lemma crossmul_le_addsquare : forall a b, 0<=a -> 0<=b -> b*a+a*b <= a*a+b*b.
+Proof.
+ assert (AUX : forall a b, 0<=a<=b -> b*a+a*b <= a*a+b*b).
+ intros a b (Ha,H).
+ destruct (le_exists_sub _ _ H) as (d & EQ & Hd).
+ rewrite EQ.
+ rewrite 2 mul_add_distr_r.
+ rewrite !add_assoc. apply add_le_mono_r.
+ rewrite add_comm. apply add_le_mono_l.
+ apply mul_le_mono_nonneg_l; trivial. order.
+ intros a b Ha Hb.
+ destruct (le_gt_cases a b).
+ apply AUX; split; order.
+ rewrite (add_comm (b*a)), (add_comm (a*a)).
+ apply AUX; split; order.
+Qed.
+
+Lemma add_square_le : forall a b, 0<=a -> 0<=b ->
+ a*a + b*b <= (a+b)*(a+b).
+Proof.
+ intros a b Ha Hb.
+ rewrite mul_add_distr_r, !mul_add_distr_l.
+ rewrite add_assoc.
+ apply add_le_mono_r.
+ rewrite <- add_assoc.
+ rewrite <- (add_0_r (a*a)) at 1.
+ apply add_le_mono_l.
+ apply add_nonneg_nonneg; now apply mul_nonneg_nonneg.
+Qed.
+
+Lemma square_add_le : forall a b, 0<=a -> 0<=b ->
+ (a+b)*(a+b) <= 2*(a*a + b*b).
+Proof.
+ intros a b Ha Hb.
+ rewrite !mul_add_distr_l, !mul_add_distr_r. nzsimpl'.
+ rewrite <- !add_assoc. apply add_le_mono_l.
+ rewrite !add_assoc. apply add_le_mono_r.
+ apply crossmul_le_addsquare; order.
Qed.
-Theorem mul_2_mono_l : forall n m, n < m -> 1 + (1 + 1) * n < (1 + 1) * m.
+Lemma quadmul_le_squareadd : forall a b, 0<=a -> 0<=b ->
+ 2*2*a*b <= (a+b)*(a+b).
Proof.
-intros n m. rewrite <- le_succ_l, (mul_le_mono_pos_l (S n) m (1 + 1)).
-rewrite !mul_add_distr_r; nzsimpl; now rewrite le_succ_l.
-apply add_pos_pos; now apply lt_0_1.
+ intros.
+ nzsimpl'.
+ rewrite !mul_add_distr_l, !mul_add_distr_r.
+ rewrite (add_comm _ (b*b)), add_assoc.
+ apply add_le_mono_r.
+ rewrite (add_shuffle0 (a*a)), (mul_comm b a).
+ apply add_le_mono_r.
+ rewrite (mul_comm a b) at 1.
+ now apply crossmul_le_addsquare.
Qed.
-End NZMulOrderPropSig.
+End NZMulOrderProp.
diff --git a/theories/Numbers/NatInt/NZOrder.v b/theories/Numbers/NatInt/NZOrder.v
index 07805772..8cf5b26f 100644
--- a/theories/Numbers/NatInt/NZOrder.v
+++ b/theories/Numbers/NatInt/NZOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,28 +8,26 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NZAxioms NZBase Decidable OrdersTac.
-Module Type NZOrderPropSig
- (Import NZ : NZOrdSig')(Import NZBase : NZBasePropSig NZ).
+Module Type NZOrderProp
+ (Import NZ : NZOrdSig')(Import NZBase : NZBaseProp NZ).
Instance le_wd : Proper (eq==>eq==>iff) le.
Proof.
-intros n n' Hn m m' Hm. rewrite !lt_eq_cases, !Hn, !Hm; auto with *.
+intros n n' Hn m m' Hm. now rewrite <- !lt_succ_r, Hn, Hm.
Qed.
Ltac le_elim H := rewrite lt_eq_cases in H; destruct H as [H | H].
Theorem lt_le_incl : forall n m, n < m -> n <= m.
Proof.
-intros; apply <- lt_eq_cases; now left.
+intros. apply lt_eq_cases. now left.
Qed.
Theorem le_refl : forall n, n <= n.
Proof.
-intro; apply <- lt_eq_cases; now right.
+intro. apply lt_eq_cases. now right.
Qed.
Theorem lt_succ_diag_r : forall n, n < S n.
@@ -99,7 +97,7 @@ intros n m; nzinduct n m.
intros H; false_hyp H lt_irrefl.
intro n; split; intros H H1 H2.
apply lt_succ_r in H2. le_elim H2.
-apply H; auto. apply -> le_succ_l. now apply lt_le_incl.
+apply H; auto. apply le_succ_l. now apply lt_le_incl.
rewrite H2 in H1. false_hyp H1 nlt_succ_diag_l.
apply le_succ_l in H1. le_elim H1.
apply H; auto. rewrite lt_succ_r. now apply lt_le_incl.
@@ -148,7 +146,8 @@ Definition lt_compat := lt_wd.
Definition lt_total := lt_trichotomy.
Definition le_lteq := lt_eq_cases.
-Module OrderElts <: TotalOrder.
+Module Private_OrderTac.
+Module Elts <: TotalOrder.
Definition t := t.
Definition eq := eq.
Definition lt := lt.
@@ -158,9 +157,10 @@ Module OrderElts <: TotalOrder.
Definition lt_compat := lt_compat.
Definition lt_total := lt_total.
Definition le_lteq := le_lteq.
-End OrderElts.
-Module OrderTac := !MakeOrderTac OrderElts.
-Ltac order := OrderTac.order.
+End Elts.
+Module Tac := !MakeOrderTac Elts.
+End Private_OrderTac.
+Ltac order := Private_OrderTac.Tac.order.
(** Some direct consequences of [order]. *)
@@ -208,12 +208,12 @@ Qed.
Theorem lt_succ_l : forall n m, S n < m -> n < m.
Proof.
-intros n m H; apply -> le_succ_l; order.
+intros n m H; apply le_succ_l; order.
Qed.
Theorem le_le_succ_r : forall n m, n <= m -> n <= S m.
Proof.
-intros n m LE. rewrite <- lt_succ_r in LE. order.
+intros n m LE. apply lt_succ_r in LE. order.
Qed.
Theorem lt_lt_succ_r : forall n m, n < m -> n < S m.
@@ -233,19 +233,37 @@ Qed.
Theorem lt_0_1 : 0 < 1.
Proof.
-apply lt_succ_diag_r.
+rewrite one_succ. apply lt_succ_diag_r.
Qed.
Theorem le_0_1 : 0 <= 1.
Proof.
-apply le_succ_diag_r.
+apply lt_le_incl, lt_0_1.
Qed.
-Theorem lt_1_l : forall n m, 0 < n -> n < m -> 1 < m.
+Theorem lt_1_2 : 1 < 2.
+Proof.
+rewrite two_succ. apply lt_succ_diag_r.
+Qed.
+
+Theorem lt_0_2 : 0 < 2.
+Proof.
+transitivity 1. apply lt_0_1. apply lt_1_2.
+Qed.
+
+Theorem le_0_2 : 0 <= 2.
Proof.
-intros n m H1 H2. apply <- le_succ_l in H1. order.
+apply lt_le_incl, lt_0_2.
Qed.
+(** The order tactic enriched with some knowledge of 0,1,2 *)
+
+Ltac order' := generalize lt_0_1 lt_1_2; order.
+
+Theorem lt_1_l : forall n m, 0 < n -> n < m -> 1 < m.
+Proof.
+intros n m H1 H2. rewrite <- le_succ_l, <- one_succ in H1. order.
+Qed.
(** More Trichotomy, decidability and double negation elimination. *)
@@ -347,7 +365,7 @@ Proof.
intro z; nzinduct n z.
order.
intro n; split; intros IH m H1 H2.
-apply -> le_succ_r in H2. destruct H2 as [H2 | H2].
+apply le_succ_r in H2. destruct H2 as [H2 | H2].
now apply IH. exists n. now split; [| rewrite <- lt_succ_r; rewrite <- H2].
apply IH. assumption. now apply le_le_succ_r.
Qed.
@@ -359,6 +377,13 @@ intros z n H; apply lt_exists_pred_strong with (z := z) (n := n).
assumption. apply le_refl.
Qed.
+Lemma lt_succ_pred : forall z n, z < n -> S (P n) == n.
+Proof.
+ intros z n H.
+ destruct (lt_exists_pred _ _ H) as (n' & EQ & LE).
+ rewrite EQ. now rewrite pred_succ.
+Qed.
+
(** Stronger variant of induction with assumptions n >= 0 (n < 0)
in the induction step *)
@@ -390,14 +415,14 @@ Qed.
Lemma rs'_rs'' : right_step' -> right_step''.
Proof.
intros RS' n; split; intros H1 m H2 H3.
-apply -> lt_succ_r in H3; le_elim H3;
+apply lt_succ_r in H3; le_elim H3;
[now apply H1 | rewrite H3 in *; now apply RS'].
apply H1; [assumption | now apply lt_lt_succ_r].
Qed.
Lemma rbase : A' z.
Proof.
-intros m H1 H2. apply -> le_ngt in H1. false_hyp H2 H1.
+intros m H1 H2. apply le_ngt in H1. false_hyp H2 H1.
Qed.
Lemma A'A_right : (forall n, A' n) -> forall n, z <= n -> A n.
@@ -449,28 +474,28 @@ Let left_step'' := forall n, A' n <-> A' (S n).
Lemma ls_ls' : A z -> left_step -> left_step'.
Proof.
intros Az LS n H1 H2. le_elim H1.
-apply LS; trivial. apply H2; [now apply <- le_succ_l | now apply eq_le_incl].
+apply LS; trivial. apply H2; [now apply le_succ_l | now apply eq_le_incl].
rewrite H1; apply Az.
Qed.
Lemma ls'_ls'' : left_step' -> left_step''.
Proof.
intros LS' n; split; intros H1 m H2 H3.
-apply -> le_succ_l in H3. apply lt_le_incl in H3. now apply H1.
+apply le_succ_l in H3. apply lt_le_incl in H3. now apply H1.
le_elim H3.
-apply <- le_succ_l in H3. now apply H1.
+apply le_succ_l in H3. now apply H1.
rewrite <- H3 in *; now apply LS'.
Qed.
Lemma lbase : A' (S z).
Proof.
-intros m H1 H2. apply -> le_succ_l in H2.
-apply -> le_ngt in H1. false_hyp H2 H1.
+intros m H1 H2. apply le_succ_l in H2.
+apply le_ngt in H1. false_hyp H2 H1.
Qed.
Lemma A'A_left : (forall n, A' n) -> forall n, n <= z -> A n.
Proof.
-intros H1 n H2. apply H1 with (n := n); [assumption | now apply eq_le_incl].
+intros H1 n H2. apply (H1 n); [assumption | now apply eq_le_incl].
Qed.
Theorem strong_left_induction: left_step' -> forall n, n <= z -> A n.
@@ -527,8 +552,8 @@ Theorem order_induction' :
forall n, A n.
Proof.
intros Az AS AP n; apply order_induction; try assumption.
-intros m H1 H2. apply AP in H2; [| now apply <- le_succ_l].
-apply -> (A_wd (P (S m)) m); [assumption | apply pred_succ].
+intros m H1 H2. apply AP in H2; [|now apply le_succ_l].
+now rewrite pred_succ in H2.
Qed.
End Center.
@@ -555,11 +580,11 @@ Theorem lt_ind : forall (n : t),
forall m, n < m -> A m.
Proof.
intros n H1 H2 m H3.
-apply right_induction with (S n); [assumption | | now apply <- le_succ_l].
-intros; apply H2; try assumption. now apply -> le_succ_l.
+apply right_induction with (S n); [assumption | | now apply le_succ_l].
+intros; apply H2; try assumption. now apply le_succ_l.
Qed.
-(** Elimintation principle for <= *)
+(** Elimination principle for <= *)
Theorem le_ind : forall (n : t),
A n ->
@@ -582,8 +607,8 @@ Section WF.
Variable z : t.
-Let Rlt (n m : t) := z <= n /\ n < m.
-Let Rgt (n m : t) := m < n /\ n <= z.
+Let Rlt (n m : t) := z <= n < m.
+Let Rgt (n m : t) := m < n <= z.
Instance Rlt_wd : Proper (eq ==> eq ==> iff) Rlt.
Proof.
@@ -595,25 +620,13 @@ Proof.
intros x1 x2 H1 x3 x4 H2; unfold Rgt; rewrite H1; now rewrite H2.
Qed.
-Instance Acc_lt_wd : Proper (eq==>iff) (Acc Rlt).
-Proof.
-intros x1 x2 H; split; intro H1; destruct H1 as [H2];
-constructor; intros; apply H2; now (rewrite H || rewrite <- H).
-Qed.
-
-Instance Acc_gt_wd : Proper (eq==>iff) (Acc Rgt).
-Proof.
-intros x1 x2 H; split; intro H1; destruct H1 as [H2];
-constructor; intros; apply H2; now (rewrite H || rewrite <- H).
-Qed.
-
Theorem lt_wf : well_founded Rlt.
Proof.
unfold well_founded.
apply strong_right_induction' with (z := z).
-apply Acc_lt_wd.
+auto with typeclass_instances.
intros n H; constructor; intros y [H1 H2].
-apply <- nle_gt in H2. elim H2. now apply le_trans with z.
+apply nle_gt in H2. elim H2. now apply le_trans with z.
intros n H1 H2; constructor; intros m [H3 H4]. now apply H2.
Qed.
@@ -621,24 +634,20 @@ Theorem gt_wf : well_founded Rgt.
Proof.
unfold well_founded.
apply strong_left_induction' with (z := z).
-apply Acc_gt_wd.
+auto with typeclass_instances.
intros n H; constructor; intros y [H1 H2].
-apply <- nle_gt in H2. elim H2. now apply le_lt_trans with n.
+apply nle_gt in H2. elim H2. now apply le_lt_trans with n.
intros n H1 H2; constructor; intros m [H3 H4].
-apply H2. assumption. now apply <- le_succ_l.
+apply H2. assumption. now apply le_succ_l.
Qed.
End WF.
-End NZOrderPropSig.
-
-Module NZOrderPropFunct (NZ : NZOrdSig) :=
- NZBasePropSig NZ <+ NZOrderPropSig NZ.
+End NZOrderProp.
(** If we have moreover a [compare] function, we can build
an [OrderedType] structure. *)
-Module NZOrderedTypeFunct (NZ : NZDecOrdSig')
- <: DecidableTypeFull <: OrderedTypeFull :=
- NZ <+ NZOrderPropFunct <+ Compare2EqBool <+ HasEqBool2Dec.
-
+Module NZOrderedType (NZ : NZDecOrdSig')
+ <: DecidableTypeFull <: OrderedTypeFull
+ := NZ <+ NZBaseProp <+ NZOrderProp <+ Compare2EqBool <+ HasEqBool2Dec.
diff --git a/theories/Numbers/NatInt/NZParity.v b/theories/Numbers/NatInt/NZParity.v
new file mode 100644
index 00000000..29109ccb
--- /dev/null
+++ b/theories/Numbers/NatInt/NZParity.v
@@ -0,0 +1,263 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import Bool NZAxioms NZMulOrder.
+
+(** Parity functions *)
+
+Module Type NZParity (Import A : NZAxiomsSig').
+ Parameter Inline even odd : t -> bool.
+ Definition Even n := exists m, n == 2*m.
+ Definition Odd n := exists m, n == 2*m+1.
+ Axiom even_spec : forall n, even n = true <-> Even n.
+ Axiom odd_spec : forall n, odd n = true <-> Odd n.
+End NZParity.
+
+Module Type NZParityProp
+ (Import A : NZOrdAxiomsSig')
+ (Import B : NZParity A)
+ (Import C : NZMulOrderProp A).
+
+(** Morphisms *)
+
+Instance Even_wd : Proper (eq==>iff) Even.
+Proof. unfold Even. solve_proper. Qed.
+
+Instance Odd_wd : Proper (eq==>iff) Odd.
+Proof. unfold Odd. solve_proper. Qed.
+
+Instance even_wd : Proper (eq==>Logic.eq) even.
+Proof.
+ intros x x' EQ. rewrite eq_iff_eq_true, 2 even_spec. now f_equiv.
+Qed.
+
+Instance odd_wd : Proper (eq==>Logic.eq) odd.
+Proof.
+ intros x x' EQ. rewrite eq_iff_eq_true, 2 odd_spec. now f_equiv.
+Qed.
+
+(** Evenness and oddity are dual notions *)
+
+Lemma Even_or_Odd : forall x, Even x \/ Odd x.
+Proof.
+ nzinduct x.
+ left. exists 0. now nzsimpl.
+ intros x.
+ split; intros [(y,H)|(y,H)].
+ right. exists y. rewrite H. now nzsimpl.
+ left. exists (S y). rewrite H. now nzsimpl'.
+ right.
+ assert (LT : exists z, z<y).
+ destruct (lt_ge_cases 0 y) as [LT|GT]; [now exists 0 | exists x].
+ rewrite <- le_succ_l, H. nzsimpl'.
+ rewrite <- (add_0_r y) at 3. now apply add_le_mono_l.
+ destruct LT as (z,LT).
+ destruct (lt_exists_pred z y LT) as (y' & Hy' & _).
+ exists y'. rewrite <- succ_inj_wd, H, Hy'. now nzsimpl'.
+ left. exists y. rewrite <- succ_inj_wd. rewrite H. now nzsimpl.
+Qed.
+
+Lemma double_below : forall n m, n<=m -> 2*n < 2*m+1.
+Proof.
+ intros. nzsimpl'. apply lt_succ_r. now apply add_le_mono.
+Qed.
+
+Lemma double_above : forall n m, n<m -> 2*n+1 < 2*m.
+Proof.
+ intros. nzsimpl'.
+ rewrite <- le_succ_l, <- add_succ_l, <- add_succ_r.
+ apply add_le_mono; now apply le_succ_l.
+Qed.
+
+Lemma Even_Odd_False : forall x, Even x -> Odd x -> False.
+Proof.
+intros x (y,E) (z,O). rewrite O in E; clear O.
+destruct (le_gt_cases y z) as [LE|GT].
+generalize (double_below _ _ LE); order.
+generalize (double_above _ _ GT); order.
+Qed.
+
+Lemma orb_even_odd : forall n, orb (even n) (odd n) = true.
+Proof.
+ intros.
+ destruct (Even_or_Odd n) as [H|H].
+ rewrite <- even_spec in H. now rewrite H.
+ rewrite <- odd_spec in H. now rewrite H, orb_true_r.
+Qed.
+
+Lemma negb_odd : forall n, negb (odd n) = even n.
+Proof.
+ intros.
+ generalize (Even_or_Odd n) (Even_Odd_False n).
+ rewrite <- even_spec, <- odd_spec.
+ destruct (odd n), (even n); simpl; intuition.
+Qed.
+
+Lemma negb_even : forall n, negb (even n) = odd n.
+Proof.
+ intros. rewrite <- negb_odd. apply negb_involutive.
+Qed.
+
+(** Constants *)
+
+Lemma even_0 : even 0 = true.
+Proof.
+ rewrite even_spec. exists 0. now nzsimpl.
+Qed.
+
+Lemma odd_0 : odd 0 = false.
+Proof.
+ now rewrite <- negb_even, even_0.
+Qed.
+
+Lemma odd_1 : odd 1 = true.
+Proof.
+ rewrite odd_spec. exists 0. now nzsimpl'.
+Qed.
+
+Lemma even_1 : even 1 = false.
+Proof.
+ now rewrite <- negb_odd, odd_1.
+Qed.
+
+Lemma even_2 : even 2 = true.
+Proof.
+ rewrite even_spec. exists 1. now nzsimpl'.
+Qed.
+
+Lemma odd_2 : odd 2 = false.
+Proof.
+ now rewrite <- negb_even, even_2.
+Qed.
+
+(** Parity and successor *)
+
+Lemma Odd_succ : forall n, Odd (S n) <-> Even n.
+Proof.
+ split; intros (m,H).
+ exists m. apply succ_inj. now rewrite add_1_r in H.
+ exists m. rewrite add_1_r. now f_equiv.
+Qed.
+
+Lemma odd_succ : forall n, odd (S n) = even n.
+Proof.
+ intros. apply eq_iff_eq_true. rewrite even_spec, odd_spec.
+ apply Odd_succ.
+Qed.
+
+Lemma even_succ : forall n, even (S n) = odd n.
+Proof.
+ intros. now rewrite <- negb_odd, odd_succ, negb_even.
+Qed.
+
+Lemma Even_succ : forall n, Even (S n) <-> Odd n.
+Proof.
+ intros. now rewrite <- even_spec, even_succ, odd_spec.
+Qed.
+
+(** Parity and successor of successor *)
+
+Lemma Even_succ_succ : forall n, Even (S (S n)) <-> Even n.
+Proof.
+ intros. now rewrite Even_succ, Odd_succ.
+Qed.
+
+Lemma Odd_succ_succ : forall n, Odd (S (S n)) <-> Odd n.
+Proof.
+ intros. now rewrite Odd_succ, Even_succ.
+Qed.
+
+Lemma even_succ_succ : forall n, even (S (S n)) = even n.
+Proof.
+ intros. now rewrite even_succ, odd_succ.
+Qed.
+
+Lemma odd_succ_succ : forall n, odd (S (S n)) = odd n.
+Proof.
+ intros. now rewrite odd_succ, even_succ.
+Qed.
+
+(** Parity and addition *)
+
+Lemma even_add : forall n m, even (n+m) = Bool.eqb (even n) (even m).
+Proof.
+ intros.
+ case_eq (even n); case_eq (even m);
+ rewrite <- ?negb_true_iff, ?negb_even, ?odd_spec, ?even_spec;
+ intros (m',Hm) (n',Hn).
+ exists (n'+m'). now rewrite mul_add_distr_l, Hn, Hm.
+ exists (n'+m'). now rewrite mul_add_distr_l, Hn, Hm, add_assoc.
+ exists (n'+m'). now rewrite mul_add_distr_l, Hn, Hm, add_shuffle0.
+ exists (n'+m'+1). rewrite Hm,Hn. nzsimpl'. now rewrite add_shuffle1.
+Qed.
+
+Lemma odd_add : forall n m, odd (n+m) = xorb (odd n) (odd m).
+Proof.
+ intros. rewrite <- !negb_even. rewrite even_add.
+ now destruct (even n), (even m).
+Qed.
+
+(** Parity and multiplication *)
+
+Lemma even_mul : forall n m, even (mul n m) = even n || even m.
+Proof.
+ intros.
+ case_eq (even n); simpl; rewrite ?even_spec.
+ intros (n',Hn). exists (n'*m). now rewrite Hn, mul_assoc.
+ case_eq (even m); simpl; rewrite ?even_spec.
+ intros (m',Hm). exists (n*m'). now rewrite Hm, !mul_assoc, (mul_comm 2).
+ (* odd / odd *)
+ rewrite <- !negb_true_iff, !negb_even, !odd_spec.
+ intros (m',Hm) (n',Hn). exists (n'*2*m' +n'+m').
+ rewrite Hn,Hm, !mul_add_distr_l, !mul_add_distr_r, !mul_1_l, !mul_1_r.
+ now rewrite add_shuffle1, add_assoc, !mul_assoc.
+Qed.
+
+Lemma odd_mul : forall n m, odd (mul n m) = odd n && odd m.
+Proof.
+ intros. rewrite <- !negb_even. rewrite even_mul.
+ now destruct (even n), (even m).
+Qed.
+
+(** A particular case : adding by an even number *)
+
+Lemma even_add_even : forall n m, Even m -> even (n+m) = even n.
+Proof.
+ intros n m Hm. apply even_spec in Hm.
+ rewrite even_add, Hm. now destruct (even n).
+Qed.
+
+Lemma odd_add_even : forall n m, Even m -> odd (n+m) = odd n.
+Proof.
+ intros n m Hm. apply even_spec in Hm.
+ rewrite odd_add, <- (negb_even m), Hm. now destruct (odd n).
+Qed.
+
+Lemma even_add_mul_even : forall n m p, Even m -> even (n+m*p) = even n.
+Proof.
+ intros n m p Hm. apply even_spec in Hm.
+ apply even_add_even. apply even_spec. now rewrite even_mul, Hm.
+Qed.
+
+Lemma odd_add_mul_even : forall n m p, Even m -> odd (n+m*p) = odd n.
+Proof.
+ intros n m p Hm. apply even_spec in Hm.
+ apply odd_add_even. apply even_spec. now rewrite even_mul, Hm.
+Qed.
+
+Lemma even_add_mul_2 : forall n m, even (n+2*m) = even n.
+Proof.
+ intros. apply even_add_mul_even. apply even_spec, even_2.
+Qed.
+
+Lemma odd_add_mul_2 : forall n m, odd (n+2*m) = odd n.
+Proof.
+ intros. apply odd_add_mul_even. apply even_spec, even_2.
+Qed.
+
+End NZParityProp. \ No newline at end of file
diff --git a/theories/Numbers/NatInt/NZPow.v b/theories/Numbers/NatInt/NZPow.v
new file mode 100644
index 00000000..58704735
--- /dev/null
+++ b/theories/Numbers/NatInt/NZPow.v
@@ -0,0 +1,411 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Power Function *)
+
+Require Import NZAxioms NZMulOrder.
+
+(** Interface of a power function, then its specification on naturals *)
+
+Module Type Pow (Import A : Typ).
+ Parameters Inline pow : t -> t -> t.
+End Pow.
+
+Module Type PowNotation (A : Typ)(Import B : Pow A).
+ Infix "^" := pow.
+End PowNotation.
+
+Module Type Pow' (A : Typ) := Pow A <+ PowNotation A.
+
+Module Type NZPowSpec (Import A : NZOrdAxiomsSig')(Import B : Pow' A).
+ Declare Instance pow_wd : Proper (eq==>eq==>eq) pow.
+ Axiom pow_0_r : forall a, a^0 == 1.
+ Axiom pow_succ_r : forall a b, 0<=b -> a^(succ b) == a * a^b.
+ Axiom pow_neg_r : forall a b, b<0 -> a^b == 0.
+End NZPowSpec.
+
+(** The above [pow_neg_r] specification is useless (and trivially
+ provable) for N. Having it here allows to already derive
+ some slightly more general statements. *)
+
+Module Type NZPow (A : NZOrdAxiomsSig) := Pow A <+ NZPowSpec A.
+Module Type NZPow' (A : NZOrdAxiomsSig) := Pow' A <+ NZPowSpec A.
+
+(** Derived properties of power *)
+
+Module Type NZPowProp
+ (Import A : NZOrdAxiomsSig')
+ (Import B : NZPow' A)
+ (Import C : NZMulOrderProp A).
+
+Hint Rewrite pow_0_r pow_succ_r : nz.
+
+(** Power and basic constants *)
+
+Lemma pow_0_l : forall a, 0<a -> 0^a == 0.
+Proof.
+ intros a Ha.
+ destruct (lt_exists_pred _ _ Ha) as (a' & EQ & Ha').
+ rewrite EQ. now nzsimpl.
+Qed.
+
+Lemma pow_0_l' : forall a, a~=0 -> 0^a == 0.
+Proof.
+ intros a Ha.
+ destruct (lt_trichotomy a 0) as [LT|[EQ|GT]]; try order.
+ now rewrite pow_neg_r.
+ now apply pow_0_l.
+Qed.
+
+Lemma pow_1_r : forall a, a^1 == a.
+Proof.
+ intros. now nzsimpl'.
+Qed.
+
+Lemma pow_1_l : forall a, 0<=a -> 1^a == 1.
+Proof.
+ apply le_ind; intros. solve_proper.
+ now nzsimpl.
+ now nzsimpl.
+Qed.
+
+Hint Rewrite pow_1_r pow_1_l : nz.
+
+Lemma pow_2_r : forall a, a^2 == a*a.
+Proof.
+ intros. rewrite two_succ. nzsimpl; order'.
+Qed.
+
+Hint Rewrite pow_2_r : nz.
+
+(** Power and nullity *)
+
+Lemma pow_eq_0 : forall a b, 0<=b -> a^b == 0 -> a == 0.
+Proof.
+ intros a b Hb. apply le_ind with (4:=Hb).
+ solve_proper.
+ rewrite pow_0_r. order'.
+ clear b Hb. intros b Hb IH.
+ rewrite pow_succ_r by trivial.
+ intros H. apply eq_mul_0 in H. destruct H; trivial.
+ now apply IH.
+Qed.
+
+Lemma pow_nonzero : forall a b, a~=0 -> 0<=b -> a^b ~= 0.
+Proof.
+ intros a b Ha Hb. contradict Ha. now apply pow_eq_0 with b.
+Qed.
+
+Lemma pow_eq_0_iff : forall a b, a^b == 0 <-> b<0 \/ (0<b /\ a==0).
+Proof.
+ intros a b. split.
+ intros H.
+ destruct (lt_trichotomy b 0) as [Hb|[Hb|Hb]].
+ now left.
+ rewrite Hb, pow_0_r in H; order'.
+ right. split; trivial. apply pow_eq_0 with b; order.
+ intros [Hb|[Hb Ha]]. now rewrite pow_neg_r.
+ rewrite Ha. apply pow_0_l'. order.
+Qed.
+
+(** Power and addition, multiplication *)
+
+Lemma pow_add_r : forall a b c, 0<=b -> 0<=c ->
+ a^(b+c) == a^b * a^c.
+Proof.
+ intros a b c Hb. apply le_ind with (4:=Hb). solve_proper.
+ now nzsimpl.
+ clear b Hb. intros b Hb IH Hc.
+ nzsimpl; trivial.
+ rewrite IH; trivial. apply mul_assoc.
+ now apply add_nonneg_nonneg.
+Qed.
+
+Lemma pow_mul_l : forall a b c,
+ (a*b)^c == a^c * b^c.
+Proof.
+ intros a b c.
+ destruct (lt_ge_cases c 0) as [Hc|Hc].
+ rewrite !(pow_neg_r _ _ Hc). now nzsimpl.
+ apply le_ind with (4:=Hc). solve_proper.
+ now nzsimpl.
+ clear c Hc. intros c Hc IH.
+ nzsimpl; trivial.
+ rewrite IH; trivial. apply mul_shuffle1.
+Qed.
+
+Lemma pow_mul_r : forall a b c, 0<=b -> 0<=c ->
+ a^(b*c) == (a^b)^c.
+Proof.
+ intros a b c Hb. apply le_ind with (4:=Hb). solve_proper.
+ intros. now nzsimpl.
+ clear b Hb. intros b Hb IH Hc.
+ nzsimpl; trivial.
+ rewrite pow_add_r, IH, pow_mul_l; trivial. apply mul_comm.
+ now apply mul_nonneg_nonneg.
+Qed.
+
+(** Positivity *)
+
+Lemma pow_nonneg : forall a b, 0<=a -> 0<=a^b.
+Proof.
+ intros a b Ha.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ now rewrite !(pow_neg_r _ _ Hb).
+ apply le_ind with (4:=Hb). solve_proper.
+ nzsimpl; order'.
+ clear b Hb. intros b Hb IH.
+ nzsimpl; trivial. now apply mul_nonneg_nonneg.
+Qed.
+
+Lemma pow_pos_nonneg : forall a b, 0<a -> 0<=b -> 0<a^b.
+Proof.
+ intros a b Ha Hb. apply le_ind with (4:=Hb). solve_proper.
+ nzsimpl; order'.
+ clear b Hb. intros b Hb IH.
+ nzsimpl; trivial. now apply mul_pos_pos.
+Qed.
+
+(** Monotonicity *)
+
+Lemma pow_lt_mono_l : forall a b c, 0<c -> 0<=a<b -> a^c < b^c.
+Proof.
+ intros a b c Hc. apply lt_ind with (4:=Hc). solve_proper.
+ intros (Ha,H). nzsimpl; trivial; order.
+ clear c Hc. intros c Hc IH (Ha,H).
+ nzsimpl; try order.
+ apply mul_lt_mono_nonneg; trivial.
+ apply pow_nonneg; try order.
+ apply IH. now split.
+Qed.
+
+Lemma pow_le_mono_l : forall a b c, 0<=a<=b -> a^c <= b^c.
+Proof.
+ intros a b c (Ha,H).
+ destruct (lt_trichotomy c 0) as [Hc|[Hc|Hc]].
+ rewrite !(pow_neg_r _ _ Hc); now nzsimpl.
+ rewrite Hc; now nzsimpl.
+ apply lt_eq_cases in H. destruct H as [H|H]; [|now rewrite <- H].
+ apply lt_le_incl, pow_lt_mono_l; now try split.
+Qed.
+
+Lemma pow_gt_1 : forall a b, 1<a -> (0<b <-> 1<a^b).
+Proof.
+ intros a b Ha. split; intros Hb.
+ rewrite <- (pow_1_l b) by order.
+ apply pow_lt_mono_l; try split; order'.
+ destruct (lt_trichotomy b 0) as [H|[H|H]]; trivial.
+ rewrite pow_neg_r in Hb; order'.
+ rewrite H, pow_0_r in Hb. order.
+Qed.
+
+Lemma pow_lt_mono_r : forall a b c, 1<a -> 0<=c -> b<c -> a^b < a^c.
+Proof.
+ intros a b c Ha Hc H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite pow_neg_r by trivial. apply pow_pos_nonneg; order'.
+ assert (H' : b<=c) by order.
+ destruct (le_exists_sub _ _ H') as (d & EQ & Hd).
+ rewrite EQ, pow_add_r; trivial. rewrite <- (mul_1_l (a^b)) at 1.
+ apply mul_lt_mono_pos_r.
+ apply pow_pos_nonneg; order'.
+ apply pow_gt_1; trivial.
+ apply lt_eq_cases in Hd; destruct Hd as [LT|EQ']; trivial.
+ rewrite <- EQ' in *. rewrite add_0_l in EQ. order.
+Qed.
+
+(** NB: since 0^0 > 0^1, the following result isn't valid with a=0 *)
+
+Lemma pow_le_mono_r : forall a b c, 0<a -> b<=c -> a^b <= a^c.
+Proof.
+ intros a b c Ha H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite (pow_neg_r _ _ Hb). apply pow_nonneg; order.
+ apply le_succ_l in Ha; rewrite <- one_succ in Ha.
+ apply lt_eq_cases in Ha; destruct Ha as [Ha|Ha]; [|rewrite <- Ha].
+ apply lt_eq_cases in H; destruct H as [H|H]; [|now rewrite <- H].
+ apply lt_le_incl, pow_lt_mono_r; order.
+ nzsimpl; order.
+Qed.
+
+Lemma pow_le_mono : forall a b c d, 0<a<=c -> b<=d ->
+ a^b <= c^d.
+Proof.
+ intros. transitivity (a^d).
+ apply pow_le_mono_r; intuition order.
+ apply pow_le_mono_l; intuition order.
+Qed.
+
+Lemma pow_lt_mono : forall a b c d, 0<a<c -> 0<b<d ->
+ a^b < c^d.
+Proof.
+ intros a b c d (Ha,Hac) (Hb,Hbd).
+ apply le_succ_l in Ha; rewrite <- one_succ in Ha.
+ apply lt_eq_cases in Ha; destruct Ha as [Ha|Ha]; [|rewrite <- Ha].
+ transitivity (a^d).
+ apply pow_lt_mono_r; intuition order.
+ apply pow_lt_mono_l; try split; order'.
+ nzsimpl; try order. apply pow_gt_1; order.
+Qed.
+
+(** Injectivity *)
+
+Lemma pow_inj_l : forall a b c, 0<=a -> 0<=b -> 0<c ->
+ a^c == b^c -> a == b.
+Proof.
+ intros a b c Ha Hb Hc EQ.
+ destruct (lt_trichotomy a b) as [LT|[EQ'|GT]]; trivial.
+ assert (a^c < b^c) by (apply pow_lt_mono_l; try split; trivial).
+ order.
+ assert (b^c < a^c) by (apply pow_lt_mono_l; try split; trivial).
+ order.
+Qed.
+
+Lemma pow_inj_r : forall a b c, 1<a -> 0<=b -> 0<=c ->
+ a^b == a^c -> b == c.
+Proof.
+ intros a b c Ha Hb Hc EQ.
+ destruct (lt_trichotomy b c) as [LT|[EQ'|GT]]; trivial.
+ assert (a^b < a^c) by (apply pow_lt_mono_r; try split; trivial).
+ order.
+ assert (a^c < a^b) by (apply pow_lt_mono_r; try split; trivial).
+ order.
+Qed.
+
+(** Monotonicity results, both ways *)
+
+Lemma pow_lt_mono_l_iff : forall a b c, 0<=a -> 0<=b -> 0<c ->
+ (a<b <-> a^c < b^c).
+Proof.
+ intros a b c Ha Hb Hc.
+ split; intro LT.
+ apply pow_lt_mono_l; try split; trivial.
+ destruct (le_gt_cases b a) as [LE|GT]; trivial.
+ assert (b^c <= a^c) by (apply pow_le_mono_l; try split; order).
+ order.
+Qed.
+
+Lemma pow_le_mono_l_iff : forall a b c, 0<=a -> 0<=b -> 0<c ->
+ (a<=b <-> a^c <= b^c).
+Proof.
+ intros a b c Ha Hb Hc.
+ split; intro LE.
+ apply pow_le_mono_l; try split; trivial.
+ destruct (le_gt_cases a b) as [LE'|GT]; trivial.
+ assert (b^c < a^c) by (apply pow_lt_mono_l; try split; trivial).
+ order.
+Qed.
+
+Lemma pow_lt_mono_r_iff : forall a b c, 1<a -> 0<=c ->
+ (b<c <-> a^b < a^c).
+Proof.
+ intros a b c Ha Hc.
+ split; intro LT.
+ now apply pow_lt_mono_r.
+ destruct (le_gt_cases c b) as [LE|GT]; trivial.
+ assert (a^c <= a^b) by (apply pow_le_mono_r; order').
+ order.
+Qed.
+
+Lemma pow_le_mono_r_iff : forall a b c, 1<a -> 0<=c ->
+ (b<=c <-> a^b <= a^c).
+Proof.
+ intros a b c Ha Hc.
+ split; intro LE.
+ apply pow_le_mono_r; order'.
+ destruct (le_gt_cases b c) as [LE'|GT]; trivial.
+ assert (a^c < a^b) by (apply pow_lt_mono_r; order').
+ order.
+Qed.
+
+(** For any a>1, the a^x function is above the identity function *)
+
+Lemma pow_gt_lin_r : forall a b, 1<a -> 0<=b -> b < a^b.
+Proof.
+ intros a b Ha Hb. apply le_ind with (4:=Hb). solve_proper.
+ nzsimpl. order'.
+ clear b Hb. intros b Hb IH. nzsimpl; trivial.
+ rewrite <- !le_succ_l in *. rewrite <- two_succ in Ha.
+ transitivity (2*(S b)).
+ nzsimpl'. rewrite <- 2 succ_le_mono.
+ rewrite <- (add_0_l b) at 1. apply add_le_mono; order.
+ apply mul_le_mono_nonneg; trivial.
+ order'.
+ now apply lt_le_incl, lt_succ_r.
+Qed.
+
+(** Someday, we should say something about the full Newton formula.
+ In the meantime, we can at least provide some inequalities about
+ (a+b)^c.
+*)
+
+Lemma pow_add_lower : forall a b c, 0<=a -> 0<=b -> 0<c ->
+ a^c + b^c <= (a+b)^c.
+Proof.
+ intros a b c Ha Hb Hc. apply lt_ind with (4:=Hc). solve_proper.
+ nzsimpl; order.
+ clear c Hc. intros c Hc IH.
+ assert (0<=c) by order'.
+ nzsimpl; trivial.
+ transitivity ((a+b)*(a^c + b^c)).
+ rewrite mul_add_distr_r, !mul_add_distr_l.
+ apply add_le_mono.
+ rewrite <- add_0_r at 1. apply add_le_mono_l.
+ apply mul_nonneg_nonneg; trivial.
+ apply pow_nonneg; trivial.
+ rewrite <- add_0_l at 1. apply add_le_mono_r.
+ apply mul_nonneg_nonneg; trivial.
+ apply pow_nonneg; trivial.
+ apply mul_le_mono_nonneg_l; trivial.
+ now apply add_nonneg_nonneg.
+Qed.
+
+(** This upper bound can also be seen as a convexity proof for x^c :
+ image of (a+b)/2 is below the middle of the images of a and b
+*)
+
+Lemma pow_add_upper : forall a b c, 0<=a -> 0<=b -> 0<c ->
+ (a+b)^c <= 2^(pred c) * (a^c + b^c).
+Proof.
+ assert (aux : forall a b c, 0<=a<=b -> 0<c ->
+ (a + b) * (a ^ c + b ^ c) <= 2 * (a * a ^ c + b * b ^ c)).
+ (* begin *)
+ intros a b c (Ha,H) Hc.
+ rewrite !mul_add_distr_l, !mul_add_distr_r. nzsimpl'.
+ rewrite <- !add_assoc. apply add_le_mono_l.
+ rewrite !add_assoc. apply add_le_mono_r.
+ destruct (le_exists_sub _ _ H) as (d & EQ & Hd).
+ rewrite EQ.
+ rewrite 2 mul_add_distr_r.
+ rewrite !add_assoc. apply add_le_mono_r.
+ rewrite add_comm. apply add_le_mono_l.
+ apply mul_le_mono_nonneg_l; trivial.
+ apply pow_le_mono_l; try split; order.
+ (* end *)
+ intros a b c Ha Hb Hc. apply lt_ind with (4:=Hc). solve_proper.
+ nzsimpl; order.
+ clear c Hc. intros c Hc IH.
+ assert (0<=c) by order.
+ nzsimpl; trivial.
+ transitivity ((a+b)*(2^(pred c) * (a^c + b^c))).
+ apply mul_le_mono_nonneg_l; trivial.
+ now apply add_nonneg_nonneg.
+ rewrite mul_assoc. rewrite (mul_comm (a+b)).
+ assert (EQ : S (P c) == c) by (apply lt_succ_pred with 0; order').
+ assert (LE : 0 <= P c) by (now rewrite succ_le_mono, EQ, le_succ_l).
+ assert (EQ' : 2^c == 2^(P c) * 2) by (rewrite <- EQ at 1; nzsimpl'; order).
+ rewrite EQ', <- !mul_assoc.
+ apply mul_le_mono_nonneg_l.
+ apply pow_nonneg; order'.
+ destruct (le_gt_cases a b).
+ apply aux; try split; order'.
+ rewrite (add_comm a), (add_comm (a^c)), (add_comm (a*a^c)).
+ apply aux; try split; order'.
+Qed.
+
+End NZPowProp.
diff --git a/theories/Numbers/NatInt/NZProperties.v b/theories/Numbers/NatInt/NZProperties.v
index 7279325d..13c26233 100644
--- a/theories/Numbers/NatInt/NZProperties.v
+++ b/theories/Numbers/NatInt/NZProperties.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,13 +8,11 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NZProperties.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NZAxioms NZMulOrder.
(** This functor summarizes all known facts about NZ.
- For the moment it is only an alias to [NZMulOrderPropFunct], which
+ For the moment it is only an alias to [NZMulOrderProp], which
subsumes all others.
*)
-Module Type NZPropFunct := NZMulOrderPropSig.
+Module Type NZProp := NZMulOrderProp.
diff --git a/theories/Numbers/NatInt/NZSqrt.v b/theories/Numbers/NatInt/NZSqrt.v
new file mode 100644
index 00000000..6e85c689
--- /dev/null
+++ b/theories/Numbers/NatInt/NZSqrt.v
@@ -0,0 +1,734 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Square Root Function *)
+
+Require Import NZAxioms NZMulOrder.
+
+(** Interface of a sqrt function, then its specification on naturals *)
+
+Module Type Sqrt (Import A : Typ).
+ Parameter Inline sqrt : t -> t.
+End Sqrt.
+
+Module Type SqrtNotation (A : Typ)(Import B : Sqrt A).
+ Notation "√ x" := (sqrt x) (at level 6).
+End SqrtNotation.
+
+Module Type Sqrt' (A : Typ) := Sqrt A <+ SqrtNotation A.
+
+Module Type NZSqrtSpec (Import A : NZOrdAxiomsSig')(Import B : Sqrt' A).
+ Axiom sqrt_spec : forall a, 0<=a -> √a * √a <= a < S (√a) * S (√a).
+ Axiom sqrt_neg : forall a, a<0 -> √a == 0.
+End NZSqrtSpec.
+
+Module Type NZSqrt (A : NZOrdAxiomsSig) := Sqrt A <+ NZSqrtSpec A.
+Module Type NZSqrt' (A : NZOrdAxiomsSig) := Sqrt' A <+ NZSqrtSpec A.
+
+(** Derived properties of power *)
+
+Module Type NZSqrtProp
+ (Import A : NZOrdAxiomsSig')
+ (Import B : NZSqrt' A)
+ (Import C : NZMulOrderProp A).
+
+Local Notation "a ²" := (a*a) (at level 5, no associativity, format "a ²").
+
+(** First, sqrt is non-negative *)
+
+Lemma sqrt_spec_nonneg : forall b,
+ b² < (S b)² -> 0 <= b.
+Proof.
+ intros b LT.
+ destruct (le_gt_cases 0 b) as [Hb|Hb]; trivial. exfalso.
+ assert ((S b)² < b²).
+ rewrite mul_succ_l, <- (add_0_r b²).
+ apply add_lt_le_mono.
+ apply mul_lt_mono_neg_l; trivial. apply lt_succ_diag_r.
+ now apply le_succ_l.
+ order.
+Qed.
+
+Lemma sqrt_nonneg : forall a, 0<=√a.
+Proof.
+ intros. destruct (lt_ge_cases a 0) as [Ha|Ha].
+ now rewrite (sqrt_neg _ Ha).
+ apply sqrt_spec_nonneg. destruct (sqrt_spec a Ha). order.
+Qed.
+
+(** The spec of sqrt indeed determines it *)
+
+Lemma sqrt_unique : forall a b, b² <= a < (S b)² -> √a == b.
+Proof.
+ intros a b (LEb,LTb).
+ assert (Ha : 0<=a) by (transitivity b²; trivial using square_nonneg).
+ assert (Hb : 0<=b) by (apply sqrt_spec_nonneg; order).
+ assert (Ha': 0<=√a) by now apply sqrt_nonneg.
+ destruct (sqrt_spec a Ha) as (LEa,LTa).
+ assert (b <= √a).
+ apply lt_succ_r, square_lt_simpl_nonneg; [|order].
+ now apply lt_le_incl, lt_succ_r.
+ assert (√a <= b).
+ apply lt_succ_r, square_lt_simpl_nonneg; [|order].
+ now apply lt_le_incl, lt_succ_r.
+ order.
+Qed.
+
+(** Hence sqrt is a morphism *)
+
+Instance sqrt_wd : Proper (eq==>eq) sqrt.
+Proof.
+ intros x x' Hx.
+ destruct (lt_ge_cases x 0) as [H|H].
+ rewrite 2 sqrt_neg; trivial. reflexivity.
+ now rewrite <- Hx.
+ apply sqrt_unique. rewrite Hx in *. now apply sqrt_spec.
+Qed.
+
+(** An alternate specification *)
+
+Lemma sqrt_spec_alt : forall a, 0<=a -> exists r,
+ a == (√a)² + r /\ 0 <= r <= 2*√a.
+Proof.
+ intros a Ha.
+ destruct (sqrt_spec _ Ha) as (LE,LT).
+ destruct (le_exists_sub _ _ LE) as (r & Hr & Hr').
+ exists r.
+ split. now rewrite add_comm.
+ split. trivial.
+ apply (add_le_mono_r _ _ (√a)²).
+ rewrite <- Hr, add_comm.
+ generalize LT. nzsimpl'. now rewrite lt_succ_r, add_assoc.
+Qed.
+
+Lemma sqrt_unique' : forall a b c, 0<=c<=2*b ->
+ a == b² + c -> √a == b.
+Proof.
+ intros a b c (Hc,H) EQ.
+ apply sqrt_unique.
+ rewrite EQ.
+ split.
+ rewrite <- add_0_r at 1. now apply add_le_mono_l.
+ nzsimpl. apply lt_succ_r.
+ rewrite <- add_assoc. apply add_le_mono_l.
+ generalize H; now nzsimpl'.
+Qed.
+
+(** Sqrt is exact on squares *)
+
+Lemma sqrt_square : forall a, 0<=a -> √(a²) == a.
+Proof.
+ intros a Ha.
+ apply sqrt_unique' with 0.
+ split. order. apply mul_nonneg_nonneg; order'. now nzsimpl.
+Qed.
+
+(** Sqrt and predecessors of squares *)
+
+Lemma sqrt_pred_square : forall a, 0<a -> √(P a²) == P a.
+Proof.
+ intros a Ha.
+ apply sqrt_unique.
+ assert (EQ := lt_succ_pred 0 a Ha).
+ rewrite EQ. split.
+ apply lt_succ_r.
+ rewrite (lt_succ_pred 0).
+ assert (0 <= P a) by (now rewrite <- lt_succ_r, EQ).
+ assert (P a < a) by (now rewrite <- le_succ_l, EQ).
+ apply mul_lt_mono_nonneg; trivial.
+ now apply mul_pos_pos.
+ apply le_succ_l.
+ rewrite (lt_succ_pred 0). reflexivity. now apply mul_pos_pos.
+Qed.
+
+(** Sqrt is a monotone function (but not a strict one) *)
+
+Lemma sqrt_le_mono : forall a b, a <= b -> √a <= √b.
+Proof.
+ intros a b Hab.
+ destruct (lt_ge_cases a 0) as [Ha|Ha].
+ rewrite (sqrt_neg _ Ha). apply sqrt_nonneg.
+ assert (Hb : 0 <= b) by order.
+ destruct (sqrt_spec a Ha) as (LE,_).
+ destruct (sqrt_spec b Hb) as (_,LT).
+ apply lt_succ_r.
+ apply square_lt_simpl_nonneg; try order.
+ now apply lt_le_incl, lt_succ_r, sqrt_nonneg.
+Qed.
+
+(** No reverse result for <=, consider for instance √2 <= √1 *)
+
+Lemma sqrt_lt_cancel : forall a b, √a < √b -> a < b.
+Proof.
+ intros a b H.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite (sqrt_neg b Hb) in H; generalize (sqrt_nonneg a); order.
+ destruct (lt_ge_cases a 0) as [Ha|Ha]; [order|].
+ destruct (sqrt_spec a Ha) as (_,LT).
+ destruct (sqrt_spec b Hb) as (LE,_).
+ apply le_succ_l in H.
+ assert ((S (√a))² <= (√b)²).
+ apply mul_le_mono_nonneg; trivial.
+ now apply lt_le_incl, lt_succ_r, sqrt_nonneg.
+ now apply lt_le_incl, lt_succ_r, sqrt_nonneg.
+ order.
+Qed.
+
+(** When left side is a square, we have an equivalence for <= *)
+
+Lemma sqrt_le_square : forall a b, 0<=a -> 0<=b -> (b²<=a <-> b <= √a).
+Proof.
+ intros a b Ha Hb. split; intros H.
+ rewrite <- (sqrt_square b); trivial.
+ now apply sqrt_le_mono.
+ destruct (sqrt_spec a Ha) as (LE,LT).
+ transitivity (√a)²; trivial.
+ now apply mul_le_mono_nonneg.
+Qed.
+
+(** When right side is a square, we have an equivalence for < *)
+
+Lemma sqrt_lt_square : forall a b, 0<=a -> 0<=b -> (a<b² <-> √a < b).
+Proof.
+ intros a b Ha Hb. split; intros H.
+ destruct (sqrt_spec a Ha) as (LE,_).
+ apply square_lt_simpl_nonneg; try order.
+ rewrite <- (sqrt_square b Hb) in H.
+ now apply sqrt_lt_cancel.
+Qed.
+
+(** Sqrt and basic constants *)
+
+Lemma sqrt_0 : √0 == 0.
+Proof.
+ rewrite <- (mul_0_l 0) at 1. now apply sqrt_square.
+Qed.
+
+Lemma sqrt_1 : √1 == 1.
+Proof.
+ rewrite <- (mul_1_l 1) at 1. apply sqrt_square. order'.
+Qed.
+
+Lemma sqrt_2 : √2 == 1.
+Proof.
+ apply sqrt_unique' with 1. nzsimpl; split; order'. now nzsimpl'.
+Qed.
+
+Lemma sqrt_pos : forall a, 0 < √a <-> 0 < a.
+Proof.
+ intros a. split; intros Ha. apply sqrt_lt_cancel. now rewrite sqrt_0.
+ rewrite <- le_succ_l, <- one_succ, <- sqrt_1. apply sqrt_le_mono.
+ now rewrite one_succ, le_succ_l.
+Qed.
+
+Lemma sqrt_lt_lin : forall a, 1<a -> √a<a.
+Proof.
+ intros a Ha. rewrite <- sqrt_lt_square; try order'.
+ rewrite <- (mul_1_r a) at 1.
+ rewrite <- mul_lt_mono_pos_l; order'.
+Qed.
+
+Lemma sqrt_le_lin : forall a, 0<=a -> √a<=a.
+Proof.
+ intros a Ha.
+ destruct (le_gt_cases a 0) as [H|H].
+ setoid_replace a with 0 by order. now rewrite sqrt_0.
+ destruct (le_gt_cases a 1) as [H'|H'].
+ rewrite <- le_succ_l, <- one_succ in H.
+ setoid_replace a with 1 by order. now rewrite sqrt_1.
+ now apply lt_le_incl, sqrt_lt_lin.
+Qed.
+
+(** Sqrt and multiplication. *)
+
+(** Due to rounding error, we don't have the usual √(a*b) = √a*√b
+ but only lower and upper bounds. *)
+
+Lemma sqrt_mul_below : forall a b, √a * √b <= √(a*b).
+Proof.
+ intros a b.
+ destruct (lt_ge_cases a 0) as [Ha|Ha].
+ rewrite (sqrt_neg a Ha). nzsimpl. apply sqrt_nonneg.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite (sqrt_neg b Hb). nzsimpl. apply sqrt_nonneg.
+ assert (Ha':=sqrt_nonneg a).
+ assert (Hb':=sqrt_nonneg b).
+ apply sqrt_le_square; try now apply mul_nonneg_nonneg.
+ rewrite mul_shuffle1.
+ apply mul_le_mono_nonneg; try now apply mul_nonneg_nonneg.
+ now apply sqrt_spec.
+ now apply sqrt_spec.
+Qed.
+
+Lemma sqrt_mul_above : forall a b, 0<=a -> 0<=b -> √(a*b) < S (√a) * S (√b).
+Proof.
+ intros a b Ha Hb.
+ apply sqrt_lt_square.
+ now apply mul_nonneg_nonneg.
+ apply mul_nonneg_nonneg.
+ now apply lt_le_incl, lt_succ_r, sqrt_nonneg.
+ now apply lt_le_incl, lt_succ_r, sqrt_nonneg.
+ rewrite mul_shuffle1.
+ apply mul_lt_mono_nonneg; trivial; now apply sqrt_spec.
+Qed.
+
+(** And we can't find better approximations in general.
+ - The lower bound is exact for squares
+ - Concerning the upper bound, for any c>0, take a=b=c²-1,
+ then √(a*b) = c² -1 while S √a = S √b = c
+*)
+
+(** Sqrt and successor :
+ - the sqrt function climbs by at most 1 at a time
+ - otherwise it stays at the same value
+ - the +1 steps occur for squares
+*)
+
+Lemma sqrt_succ_le : forall a, 0<=a -> √(S a) <= S (√a).
+Proof.
+ intros a Ha.
+ apply lt_succ_r.
+ apply sqrt_lt_square.
+ now apply le_le_succ_r.
+ apply le_le_succ_r, le_le_succ_r, sqrt_nonneg.
+ rewrite <- (add_1_l (S (√a))).
+ apply lt_le_trans with (1²+(S (√a))²).
+ rewrite mul_1_l, add_1_l, <- succ_lt_mono.
+ now apply sqrt_spec.
+ apply add_square_le. order'. apply le_le_succ_r, sqrt_nonneg.
+Qed.
+
+Lemma sqrt_succ_or : forall a, 0<=a -> √(S a) == S (√a) \/ √(S a) == √a.
+Proof.
+ intros a Ha.
+ destruct (le_gt_cases (√(S a)) (√a)) as [H|H].
+ right. generalize (sqrt_le_mono _ _ (le_succ_diag_r a)); order.
+ left. apply le_succ_l in H. generalize (sqrt_succ_le a Ha); order.
+Qed.
+
+Lemma sqrt_eq_succ_iff_square : forall a, 0<=a ->
+ (√(S a) == S (√a) <-> exists b, 0<b /\ S a == b²).
+Proof.
+ intros a Ha. split.
+ intros EQ. exists (S (√a)).
+ split. apply lt_succ_r, sqrt_nonneg.
+ generalize (proj2 (sqrt_spec a Ha)). rewrite <- le_succ_l.
+ assert (Ha' : 0 <= S a) by now apply le_le_succ_r.
+ generalize (proj1 (sqrt_spec (S a) Ha')). rewrite EQ; order.
+ intros (b & Hb & H).
+ rewrite H. rewrite sqrt_square; try order.
+ symmetry.
+ rewrite <- (lt_succ_pred 0 b Hb). f_equiv.
+ rewrite <- (lt_succ_pred 0 b²) in H. apply succ_inj in H.
+ now rewrite H, sqrt_pred_square.
+ now apply mul_pos_pos.
+Qed.
+
+(** Sqrt and addition *)
+
+Lemma sqrt_add_le : forall a b, √(a+b) <= √a + √b.
+Proof.
+ assert (AUX : forall a b, a<0 -> √(a+b) <= √a + √b).
+ intros a b Ha. rewrite (sqrt_neg a Ha). nzsimpl.
+ apply sqrt_le_mono.
+ rewrite <- (add_0_l b) at 2.
+ apply add_le_mono_r; order.
+ intros a b.
+ destruct (lt_ge_cases a 0) as [Ha|Ha]. now apply AUX.
+ destruct (lt_ge_cases b 0) as [Hb|Hb].
+ rewrite (add_comm a), (add_comm (√a)); now apply AUX.
+ assert (Ha':=sqrt_nonneg a).
+ assert (Hb':=sqrt_nonneg b).
+ rewrite <- lt_succ_r.
+ apply sqrt_lt_square.
+ now apply add_nonneg_nonneg.
+ now apply lt_le_incl, lt_succ_r, add_nonneg_nonneg.
+ destruct (sqrt_spec a Ha) as (_,LTa).
+ destruct (sqrt_spec b Hb) as (_,LTb).
+ revert LTa LTb. nzsimpl. rewrite 3 lt_succ_r.
+ intros LTa LTb.
+ assert (H:=add_le_mono _ _ _ _ LTa LTb).
+ etransitivity; [eexact H|]. clear LTa LTb H.
+ rewrite <- (add_assoc _ (√a) (√a)).
+ rewrite <- (add_assoc _ (√b) (√b)).
+ rewrite add_shuffle1.
+ rewrite <- (add_assoc _ (√a + √b)).
+ rewrite (add_shuffle1 (√a) (√b)).
+ apply add_le_mono_r.
+ now apply add_square_le.
+Qed.
+
+(** convexity inequality for sqrt: sqrt of middle is above middle
+ of square roots. *)
+
+Lemma add_sqrt_le : forall a b, 0<=a -> 0<=b -> √a + √b <= √(2*(a+b)).
+Proof.
+ intros a b Ha Hb.
+ assert (Ha':=sqrt_nonneg a).
+ assert (Hb':=sqrt_nonneg b).
+ apply sqrt_le_square.
+ apply mul_nonneg_nonneg. order'. now apply add_nonneg_nonneg.
+ now apply add_nonneg_nonneg.
+ transitivity (2*((√a)² + (√b)²)).
+ now apply square_add_le.
+ apply mul_le_mono_nonneg_l. order'.
+ apply add_le_mono; now apply sqrt_spec.
+Qed.
+
+End NZSqrtProp.
+
+Module Type NZSqrtUpProp
+ (Import A : NZDecOrdAxiomsSig')
+ (Import B : NZSqrt' A)
+ (Import C : NZMulOrderProp A)
+ (Import D : NZSqrtProp A B C).
+
+(** * [sqrt_up] : a square root that rounds up instead of down *)
+
+Local Notation "a ²" := (a*a) (at level 5, no associativity, format "a ²").
+
+(** For once, we define instead of axiomatizing, thanks to sqrt *)
+
+Definition sqrt_up a :=
+ match compare 0 a with
+ | Lt => S √(P a)
+ | _ => 0
+ end.
+
+Local Notation "√° a" := (sqrt_up a) (at level 6, no associativity).
+
+Lemma sqrt_up_eqn0 : forall a, a<=0 -> √°a == 0.
+Proof.
+ intros a Ha. unfold sqrt_up. case compare_spec; try order.
+Qed.
+
+Lemma sqrt_up_eqn : forall a, 0<a -> √°a == S √(P a).
+Proof.
+ intros a Ha. unfold sqrt_up. case compare_spec; try order.
+Qed.
+
+Lemma sqrt_up_spec : forall a, 0<a -> (P √°a)² < a <= (√°a)².
+Proof.
+ intros a Ha.
+ rewrite sqrt_up_eqn, pred_succ; trivial.
+ assert (Ha' := lt_succ_pred 0 a Ha).
+ rewrite <- Ha' at 3 4.
+ rewrite le_succ_l, lt_succ_r.
+ apply sqrt_spec.
+ now rewrite <- lt_succ_r, Ha'.
+Qed.
+
+(** First, [sqrt_up] is non-negative *)
+
+Lemma sqrt_up_nonneg : forall a, 0<=√°a.
+Proof.
+ intros. destruct (le_gt_cases a 0) as [Ha|Ha].
+ now rewrite sqrt_up_eqn0.
+ rewrite sqrt_up_eqn; trivial. apply le_le_succ_r, sqrt_nonneg.
+Qed.
+
+(** [sqrt_up] is a morphism *)
+
+Instance sqrt_up_wd : Proper (eq==>eq) sqrt_up.
+Proof.
+ assert (Proper (eq==>eq==>Logic.eq) compare).
+ intros x x' Hx y y' Hy. do 2 case compare_spec; trivial; order.
+ intros x x' Hx. unfold sqrt_up. rewrite Hx. case compare; now rewrite ?Hx.
+Qed.
+
+(** The spec of [sqrt_up] indeed determines it *)
+
+Lemma sqrt_up_unique : forall a b, 0<b -> (P b)² < a <= b² -> √°a == b.
+Proof.
+ intros a b Hb (LEb,LTb).
+ assert (Ha : 0<a)
+ by (apply le_lt_trans with (P b)²; trivial using square_nonneg).
+ rewrite sqrt_up_eqn; trivial.
+ assert (Hb' := lt_succ_pred 0 b Hb).
+ rewrite <- Hb'. f_equiv. apply sqrt_unique.
+ rewrite <- le_succ_l, <- lt_succ_r, Hb'.
+ rewrite (lt_succ_pred 0 a Ha). now split.
+Qed.
+
+(** [sqrt_up] is exact on squares *)
+
+Lemma sqrt_up_square : forall a, 0<=a -> √°(a²) == a.
+Proof.
+ intros a Ha.
+ le_elim Ha.
+ rewrite sqrt_up_eqn by (now apply mul_pos_pos).
+ rewrite sqrt_pred_square; trivial. apply (lt_succ_pred 0); trivial.
+ rewrite sqrt_up_eqn0; trivial. rewrite <- Ha. now nzsimpl.
+Qed.
+
+(** [sqrt_up] and successors of squares *)
+
+Lemma sqrt_up_succ_square : forall a, 0<=a -> √°(S a²) == S a.
+Proof.
+ intros a Ha.
+ rewrite sqrt_up_eqn by (now apply lt_succ_r, mul_nonneg_nonneg).
+ now rewrite pred_succ, sqrt_square.
+Qed.
+
+(** Basic constants *)
+
+Lemma sqrt_up_0 : √°0 == 0.
+Proof.
+ rewrite <- (mul_0_l 0) at 1. now apply sqrt_up_square.
+Qed.
+
+Lemma sqrt_up_1 : √°1 == 1.
+Proof.
+ rewrite <- (mul_1_l 1) at 1. apply sqrt_up_square. order'.
+Qed.
+
+Lemma sqrt_up_2 : √°2 == 2.
+Proof.
+ rewrite sqrt_up_eqn by order'.
+ now rewrite two_succ, pred_succ, sqrt_1.
+Qed.
+
+(** Links between sqrt and [sqrt_up] *)
+
+Lemma le_sqrt_sqrt_up : forall a, √a <= √°a.
+Proof.
+ intros a. unfold sqrt_up. case compare_spec; intros H.
+ rewrite <- H, sqrt_0. order.
+ rewrite <- (lt_succ_pred 0 a H) at 1. apply sqrt_succ_le.
+ apply lt_succ_r. now rewrite (lt_succ_pred 0 a H).
+ now rewrite sqrt_neg.
+Qed.
+
+Lemma le_sqrt_up_succ_sqrt : forall a, √°a <= S (√a).
+Proof.
+ intros a. unfold sqrt_up.
+ case compare_spec; intros H; try apply le_le_succ_r, sqrt_nonneg.
+ rewrite <- succ_le_mono. apply sqrt_le_mono.
+ rewrite <- (lt_succ_pred 0 a H) at 2. apply le_succ_diag_r.
+Qed.
+
+Lemma sqrt_sqrt_up_spec : forall a, 0<=a -> (√a)² <= a <= (√°a)².
+Proof.
+ intros a H. split.
+ now apply sqrt_spec.
+ le_elim H.
+ now apply sqrt_up_spec.
+ now rewrite <-H, sqrt_up_0, mul_0_l.
+Qed.
+
+Lemma sqrt_sqrt_up_exact :
+ forall a, 0<=a -> (√a == √°a <-> exists b, 0<=b /\ a == b²).
+Proof.
+ intros a Ha.
+ split. intros. exists √a.
+ split. apply sqrt_nonneg.
+ generalize (sqrt_sqrt_up_spec a Ha). rewrite <-H. destruct 1; order.
+ intros (b & Hb & Hb'). rewrite Hb'.
+ now rewrite sqrt_square, sqrt_up_square.
+Qed.
+
+(** [sqrt_up] is a monotone function (but not a strict one) *)
+
+Lemma sqrt_up_le_mono : forall a b, a <= b -> √°a <= √°b.
+Proof.
+ intros a b H.
+ destruct (le_gt_cases a 0) as [Ha|Ha].
+ rewrite (sqrt_up_eqn0 _ Ha). apply sqrt_up_nonneg.
+ rewrite 2 sqrt_up_eqn by order. rewrite <- succ_le_mono.
+ apply sqrt_le_mono, succ_le_mono. rewrite 2 (lt_succ_pred 0); order.
+Qed.
+
+(** No reverse result for <=, consider for instance √°3 <= √°2 *)
+
+Lemma sqrt_up_lt_cancel : forall a b, √°a < √°b -> a < b.
+Proof.
+ intros a b H.
+ destruct (le_gt_cases b 0) as [Hb|Hb].
+ rewrite (sqrt_up_eqn0 _ Hb) in H; generalize (sqrt_up_nonneg a); order.
+ destruct (le_gt_cases a 0) as [Ha|Ha]; [order|].
+ rewrite <- (lt_succ_pred 0 a Ha), <- (lt_succ_pred 0 b Hb), <- succ_lt_mono.
+ apply sqrt_lt_cancel, succ_lt_mono. now rewrite <- 2 sqrt_up_eqn.
+Qed.
+
+(** When left side is a square, we have an equivalence for < *)
+
+Lemma sqrt_up_lt_square : forall a b, 0<=a -> 0<=b -> (b² < a <-> b < √°a).
+Proof.
+ intros a b Ha Hb. split; intros H.
+ destruct (sqrt_up_spec a) as (LE,LT).
+ apply le_lt_trans with b²; trivial using square_nonneg.
+ apply square_lt_simpl_nonneg; try order. apply sqrt_up_nonneg.
+ apply sqrt_up_lt_cancel. now rewrite sqrt_up_square.
+Qed.
+
+(** When right side is a square, we have an equivalence for <= *)
+
+Lemma sqrt_up_le_square : forall a b, 0<=a -> 0<=b -> (a <= b² <-> √°a <= b).
+Proof.
+ intros a b Ha Hb. split; intros H.
+ rewrite <- (sqrt_up_square b Hb).
+ now apply sqrt_up_le_mono.
+ apply square_le_mono_nonneg in H; [|now apply sqrt_up_nonneg].
+ transitivity (√°a)²; trivial. now apply sqrt_sqrt_up_spec.
+Qed.
+
+Lemma sqrt_up_pos : forall a, 0 < √°a <-> 0 < a.
+Proof.
+ intros a. split; intros Ha. apply sqrt_up_lt_cancel. now rewrite sqrt_up_0.
+ rewrite <- le_succ_l, <- one_succ, <- sqrt_up_1. apply sqrt_up_le_mono.
+ now rewrite one_succ, le_succ_l.
+Qed.
+
+Lemma sqrt_up_lt_lin : forall a, 2<a -> √°a < a.
+Proof.
+ intros a Ha.
+ rewrite sqrt_up_eqn by order'.
+ assert (Ha' := lt_succ_pred 2 a Ha).
+ rewrite <- Ha' at 2. rewrite <- succ_lt_mono.
+ apply sqrt_lt_lin. rewrite succ_lt_mono. now rewrite Ha', <- two_succ.
+Qed.
+
+Lemma sqrt_up_le_lin : forall a, 0<=a -> √°a<=a.
+Proof.
+ intros a Ha.
+ le_elim Ha.
+ rewrite sqrt_up_eqn; trivial. apply le_succ_l.
+ apply le_lt_trans with (P a). apply sqrt_le_lin.
+ now rewrite <- lt_succ_r, (lt_succ_pred 0).
+ rewrite <- (lt_succ_pred 0 a) at 2; trivial. apply lt_succ_diag_r.
+ now rewrite <- Ha, sqrt_up_0.
+Qed.
+
+(** [sqrt_up] and multiplication. *)
+
+(** Due to rounding error, we don't have the usual [√(a*b) = √a*√b]
+ but only lower and upper bounds. *)
+
+Lemma sqrt_up_mul_above : forall a b, 0<=a -> 0<=b -> √°(a*b) <= √°a * √°b.
+Proof.
+ intros a b Ha Hb.
+ apply sqrt_up_le_square.
+ now apply mul_nonneg_nonneg.
+ apply mul_nonneg_nonneg; apply sqrt_up_nonneg.
+ rewrite mul_shuffle1.
+ apply mul_le_mono_nonneg; trivial; now apply sqrt_sqrt_up_spec.
+Qed.
+
+Lemma sqrt_up_mul_below : forall a b, 0<a -> 0<b -> (P √°a)*(P √°b) < √°(a*b).
+Proof.
+ intros a b Ha Hb.
+ apply sqrt_up_lt_square.
+ apply mul_nonneg_nonneg; order.
+ apply mul_nonneg_nonneg; apply lt_succ_r.
+ rewrite (lt_succ_pred 0); now rewrite sqrt_up_pos.
+ rewrite (lt_succ_pred 0); now rewrite sqrt_up_pos.
+ rewrite mul_shuffle1.
+ apply mul_lt_mono_nonneg; trivial using square_nonneg;
+ now apply sqrt_up_spec.
+Qed.
+
+(** And we can't find better approximations in general.
+ - The upper bound is exact for squares
+ - Concerning the lower bound, for any c>0, take [a=b=c²+1],
+ then [√°(a*b) = c²+1] while [P √°a = P √°b = c]
+*)
+
+(** [sqrt_up] and successor :
+ - the [sqrt_up] function climbs by at most 1 at a time
+ - otherwise it stays at the same value
+ - the +1 steps occur after squares
+*)
+
+Lemma sqrt_up_succ_le : forall a, 0<=a -> √°(S a) <= S (√°a).
+Proof.
+ intros a Ha.
+ apply sqrt_up_le_square.
+ now apply le_le_succ_r.
+ apply le_le_succ_r, sqrt_up_nonneg.
+ rewrite <- (add_1_l (√°a)).
+ apply le_trans with (1²+(√°a)²).
+ rewrite mul_1_l, add_1_l, <- succ_le_mono.
+ now apply sqrt_sqrt_up_spec.
+ apply add_square_le. order'. apply sqrt_up_nonneg.
+Qed.
+
+Lemma sqrt_up_succ_or : forall a, 0<=a -> √°(S a) == S (√°a) \/ √°(S a) == √°a.
+Proof.
+ intros a Ha.
+ destruct (le_gt_cases (√°(S a)) (√°a)) as [H|H].
+ right. generalize (sqrt_up_le_mono _ _ (le_succ_diag_r a)); order.
+ left. apply le_succ_l in H. generalize (sqrt_up_succ_le a Ha); order.
+Qed.
+
+Lemma sqrt_up_eq_succ_iff_square : forall a, 0<=a ->
+ (√°(S a) == S (√°a) <-> exists b, 0<=b /\ a == b²).
+Proof.
+ intros a Ha. split.
+ intros EQ.
+ le_elim Ha.
+ exists (√°a). split. apply sqrt_up_nonneg.
+ generalize (proj2 (sqrt_up_spec a Ha)).
+ assert (Ha' : 0 < S a) by (apply lt_succ_r; order').
+ generalize (proj1 (sqrt_up_spec (S a) Ha')).
+ rewrite EQ, pred_succ, lt_succ_r. order.
+ exists 0. nzsimpl. now split.
+ intros (b & Hb & H).
+ now rewrite H, sqrt_up_succ_square, sqrt_up_square.
+Qed.
+
+(** [sqrt_up] and addition *)
+
+Lemma sqrt_up_add_le : forall a b, √°(a+b) <= √°a + √°b.
+Proof.
+ assert (AUX : forall a b, a<=0 -> √°(a+b) <= √°a + √°b).
+ intros a b Ha. rewrite (sqrt_up_eqn0 a Ha). nzsimpl.
+ apply sqrt_up_le_mono.
+ rewrite <- (add_0_l b) at 2.
+ apply add_le_mono_r; order.
+ intros a b.
+ destruct (le_gt_cases a 0) as [Ha|Ha]. now apply AUX.
+ destruct (le_gt_cases b 0) as [Hb|Hb].
+ rewrite (add_comm a), (add_comm (√°a)); now apply AUX.
+ rewrite 2 sqrt_up_eqn; trivial.
+ nzsimpl. rewrite <- succ_le_mono.
+ transitivity (√(P a) + √b).
+ rewrite <- (lt_succ_pred 0 a Ha) at 1. nzsimpl. apply sqrt_add_le.
+ apply add_le_mono_l.
+ apply le_sqrt_sqrt_up.
+ now apply add_pos_pos.
+Qed.
+
+(** Convexity-like inequality for [sqrt_up]: [sqrt_up] of middle is above middle
+ of square roots. We cannot say more, for instance take a=b=2, then
+ 2+2 <= S 3 *)
+
+Lemma add_sqrt_up_le : forall a b, 0<=a -> 0<=b -> √°a + √°b <= S √°(2*(a+b)).
+Proof.
+ intros a b Ha Hb.
+ le_elim Ha.
+ le_elim Hb.
+ rewrite 3 sqrt_up_eqn; trivial.
+ nzsimpl. rewrite <- 2 succ_le_mono.
+ etransitivity; [eapply add_sqrt_le|].
+ apply lt_succ_r. now rewrite (lt_succ_pred 0 a Ha).
+ apply lt_succ_r. now rewrite (lt_succ_pred 0 b Hb).
+ apply sqrt_le_mono.
+ apply lt_succ_r. rewrite (lt_succ_pred 0).
+ apply mul_lt_mono_pos_l. order'.
+ apply add_lt_mono.
+ apply le_succ_l. now rewrite (lt_succ_pred 0).
+ apply le_succ_l. now rewrite (lt_succ_pred 0).
+ apply mul_pos_pos. order'. now apply add_pos_pos.
+ apply mul_pos_pos. order'. now apply add_pos_pos.
+ rewrite <- Hb, sqrt_up_0. nzsimpl. apply le_le_succ_r, sqrt_up_le_mono.
+ rewrite <- (mul_1_l a) at 1. apply mul_le_mono_nonneg_r; order'.
+ rewrite <- Ha, sqrt_up_0. nzsimpl. apply le_le_succ_r, sqrt_up_le_mono.
+ rewrite <- (mul_1_l b) at 1. apply mul_le_mono_nonneg_r; order'.
+Qed.
+
+End NZSqrtUpProp.
diff --git a/theories/Numbers/Natural/Abstract/NAdd.v b/theories/Numbers/Natural/Abstract/NAdd.v
index 4185de95..72e09f15 100644
--- a/theories/Numbers/Natural/Abstract/NAdd.v
+++ b/theories/Numbers/Natural/Abstract/NAdd.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NAdd.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NBase.
-Module NAddPropFunct (Import N : NAxiomsSig').
-Include NBasePropFunct N.
+Module NAddProp (Import N : NAxiomsMiniSig').
+Include NBaseProp N.
(** For theorems about [add] that are both valid for [N] and [Z], see [NZAdd] *)
(** Now comes theorems valid for natural numbers but not for Z *)
@@ -24,9 +22,9 @@ intros n m; induct n.
nzsimpl; intuition.
intros n IH. nzsimpl.
setoid_replace (S (n + m) == 0) with False by
- (apply -> neg_false; apply neq_succ_0).
+ (apply neg_false; apply neq_succ_0).
setoid_replace (S n == 0) with False by
- (apply -> neg_false; apply neq_succ_0). tauto.
+ (apply neg_false; apply neq_succ_0). tauto.
Qed.
Theorem eq_add_succ :
@@ -47,13 +45,13 @@ Qed.
Theorem eq_add_1 : forall n m,
n + m == 1 -> n == 1 /\ m == 0 \/ n == 0 /\ m == 1.
Proof.
-intros n m H.
+intros n m. rewrite one_succ. intro H.
assert (H1 : exists p, n + m == S p) by now exists 0.
-apply -> eq_add_succ in H1. destruct H1 as [[n' H1] | [m' H1]].
+apply eq_add_succ in H1. destruct H1 as [[n' H1] | [m' H1]].
left. rewrite H1 in H; rewrite add_succ_l in H; apply succ_inj in H.
-apply -> eq_add_0 in H. destruct H as [H2 H3]; rewrite H2 in H1; now split.
+apply eq_add_0 in H. destruct H as [H2 H3]; rewrite H2 in H1; now split.
right. rewrite H1 in H; rewrite add_succ_r in H; apply succ_inj in H.
-apply -> eq_add_0 in H. destruct H as [H2 H3]; rewrite H3 in H1; now split.
+apply eq_add_0 in H. destruct H as [H2 H3]; rewrite H3 in H1; now split.
Qed.
Theorem succ_add_discr : forall n m, m ~= S (n + m).
@@ -77,5 +75,5 @@ intros n m H; rewrite (add_comm n (P m));
rewrite (add_comm n m); now apply add_pred_l.
Qed.
-End NAddPropFunct.
+End NAddProp.
diff --git a/theories/Numbers/Natural/Abstract/NAddOrder.v b/theories/Numbers/Natural/Abstract/NAddOrder.v
index 0282a6b8..da41886f 100644
--- a/theories/Numbers/Natural/Abstract/NAddOrder.v
+++ b/theories/Numbers/Natural/Abstract/NAddOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NAddOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NOrder.
-Module NAddOrderPropFunct (Import N : NAxiomsSig').
-Include NOrderPropFunct N.
+Module NAddOrderProp (Import N : NAxiomsMiniSig').
+Include NOrderProp N.
(** Theorems true for natural numbers, not for integers *)
@@ -45,4 +43,4 @@ Proof.
intros; apply add_nonneg_pos. apply le_0_l. assumption.
Qed.
-End NAddOrderPropFunct.
+End NAddOrderProp.
diff --git a/theories/Numbers/Natural/Abstract/NAxioms.v b/theories/Numbers/Natural/Abstract/NAxioms.v
index d1cc9972..ca6ccc1b 100644
--- a/theories/Numbers/Natural/Abstract/NAxioms.v
+++ b/theories/Numbers/Natural/Abstract/NAxioms.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,32 +8,60 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NAxioms.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
+Require Export Bool NZAxioms NZParity NZPow NZSqrt NZLog NZDiv NZGcd NZBits.
-Require Export NZAxioms.
+(** From [NZ], we obtain natural numbers just by stating that [pred 0] == 0 *)
-Set Implicit Arguments.
+Module Type NAxiom (Import NZ : NZDomainSig').
+ Axiom pred_0 : P 0 == 0.
+End NAxiom.
-Module Type NAxioms (Import NZ : NZDomainSig').
+Module Type NAxiomsMiniSig := NZOrdAxiomsSig <+ NAxiom.
+Module Type NAxiomsMiniSig' := NZOrdAxiomsSig' <+ NAxiom.
-Axiom pred_0 : P 0 == 0.
+(** Let's now add some more functions and their specification *)
-Parameter Inline recursion : forall A : Type, A -> (t -> A -> A) -> t -> A.
-Implicit Arguments recursion [A].
+(** Division Function : we reuse NZDiv.DivMod and NZDiv.NZDivCommon,
+ and add to that a N-specific constraint. *)
-Declare Instance recursion_wd (A : Type) (Aeq : relation A) :
- Proper (Aeq ==> (eq==>Aeq==>Aeq) ==> eq ==> Aeq) (@recursion A).
+Module Type NDivSpecific (Import N : NAxiomsMiniSig')(Import DM : DivMod' N).
+ Axiom mod_upper_bound : forall a b, b ~= 0 -> a mod b < b.
+End NDivSpecific.
+
+(** For all other functions, the NZ axiomatizations are enough. *)
+
+(** We now group everything together. *)
+
+Module Type NAxiomsSig := NAxiomsMiniSig <+ OrderFunctions
+ <+ NZParity.NZParity <+ NZPow.NZPow <+ NZSqrt.NZSqrt <+ NZLog.NZLog2
+ <+ NZGcd.NZGcd <+ NZDiv.NZDiv <+ NZBits.NZBits <+ NZSquare.
+
+Module Type NAxiomsSig' := NAxiomsMiniSig' <+ OrderFunctions'
+ <+ NZParity.NZParity <+ NZPow.NZPow' <+ NZSqrt.NZSqrt' <+ NZLog.NZLog2
+ <+ NZGcd.NZGcd' <+ NZDiv.NZDiv' <+ NZBits.NZBits' <+ NZSquare.
+
+
+(** It could also be interesting to have a constructive recursor function. *)
+
+Module Type NAxiomsRec (Import NZ : NZDomainSig').
+
+Parameter Inline recursion : forall {A : Type}, A -> (t -> A -> A) -> t -> A.
+
+Declare Instance recursion_wd {A : Type} (Aeq : relation A) :
+ Proper (Aeq ==> (eq==>Aeq==>Aeq) ==> eq ==> Aeq) recursion.
Axiom recursion_0 :
- forall (A : Type) (a : A) (f : t -> A -> A), recursion a f 0 = a.
+ forall {A} (a : A) (f : t -> A -> A), recursion a f 0 = a.
Axiom recursion_succ :
- forall (A : Type) (Aeq : relation A) (a : A) (f : t -> A -> A),
+ forall {A} (Aeq : relation A) (a : A) (f : t -> A -> A),
Aeq a a -> Proper (eq==>Aeq==>Aeq) f ->
forall n, Aeq (recursion a f (S n)) (f n (recursion a f n)).
-End NAxioms.
+End NAxiomsRec.
-Module Type NAxiomsSig := NZOrdAxiomsSig <+ NAxioms.
-Module Type NAxiomsSig' := NZOrdAxiomsSig' <+ NAxioms.
+Module Type NAxiomsRecSig := NAxiomsMiniSig <+ NAxiomsRec.
+Module Type NAxiomsRecSig' := NAxiomsMiniSig' <+ NAxiomsRec.
+Module Type NAxiomsFullSig := NAxiomsSig <+ NAxiomsRec.
+Module Type NAxiomsFullSig' := NAxiomsSig' <+ NAxiomsRec.
diff --git a/theories/Numbers/Natural/Abstract/NBase.v b/theories/Numbers/Natural/Abstract/NBase.v
index efaba960..ac8a0522 100644
--- a/theories/Numbers/Natural/Abstract/NBase.v
+++ b/theories/Numbers/Natural/Abstract/NBase.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,48 +8,23 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NBase.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export Decidable.
Require Export NAxioms.
Require Import NZProperties.
-Module NBasePropFunct (Import N : NAxiomsSig').
+Module NBaseProp (Import N : NAxiomsMiniSig').
(** First, we import all known facts about both natural numbers and integers. *)
-Include NZPropFunct N.
-
-(** We prove that the successor of a number is not zero by defining a
-function (by recursion) that maps 0 to false and the successor to true *)
-
-Definition if_zero (A : Type) (a b : A) (n : N.t) : A :=
- recursion a (fun _ _ => b) n.
-
-Implicit Arguments if_zero [A].
-
-Instance if_zero_wd (A : Type) :
- Proper (Logic.eq ==> Logic.eq ==> N.eq ==> Logic.eq) (@if_zero A).
-Proof.
-intros; unfold if_zero.
-repeat red; intros. apply recursion_wd; auto. repeat red; auto.
-Qed.
-
-Theorem if_zero_0 : forall (A : Type) (a b : A), if_zero a b 0 = a.
-Proof.
-unfold if_zero; intros; now rewrite recursion_0.
-Qed.
+Include NZProp N.
-Theorem if_zero_succ :
- forall (A : Type) (a b : A) (n : N.t), if_zero a b (S n) = b.
-Proof.
-intros; unfold if_zero.
-now rewrite recursion_succ.
-Qed.
+(** From [pred_0] and order facts, we can prove that 0 isn't a successor. *)
Theorem neq_succ_0 : forall n, S n ~= 0.
Proof.
-intros n H.
-generalize (Logic.eq_refl (if_zero false true 0)).
-rewrite <- H at 1. rewrite if_zero_0, if_zero_succ; discriminate.
+ intros n EQ.
+ assert (EQ' := pred_succ n).
+ rewrite EQ, pred_0 in EQ'.
+ rewrite <- EQ' in EQ.
+ now apply (neq_succ_diag_l 0).
Qed.
Theorem neq_0_succ : forall n, 0 ~= S n.
@@ -66,7 +41,7 @@ nzinduct n.
now apply eq_le_incl.
intro n; split.
apply le_le_succ_r.
-intro H; apply -> le_succ_r in H; destruct H as [H | H].
+intro H; apply le_succ_r in H; destruct H as [H | H].
assumption.
symmetry in H; false_hyp H neq_succ_0.
Qed.
@@ -119,12 +94,11 @@ Qed.
Theorem eq_pred_0 : forall n, P n == 0 <-> n == 0 \/ n == 1.
Proof.
cases n.
-rewrite pred_0. setoid_replace (0 == 1) with False using relation iff. tauto.
-split; intro H; [symmetry in H; false_hyp H neq_succ_0 | elim H].
+rewrite pred_0. now split; [left|].
intro n. rewrite pred_succ.
-setoid_replace (S n == 0) with False using relation iff by
- (apply -> neg_false; apply neq_succ_0).
-rewrite succ_inj_wd. tauto.
+split. intros H; right. now rewrite H, one_succ.
+intros [H|H]. elim (neq_succ_0 _ H).
+apply succ_inj_wd. now rewrite <- one_succ.
Qed.
Theorem succ_pred : forall n, n ~= 0 -> S (P n) == n.
@@ -155,6 +129,7 @@ Theorem pair_induction :
A 0 -> A 1 ->
(forall n, A n -> A (S n) -> A (S (S n))) -> forall n, A n.
Proof.
+rewrite one_succ.
intros until 3.
assert (D : forall n, A n /\ A (S n)); [ |intro n; exact (proj1 (D n))].
induct n; [ | intros n [IH1 IH2]]; auto.
@@ -204,7 +179,7 @@ Ltac double_induct n m :=
try intros until n;
try intros until m;
pattern n, m; apply double_induction; clear n m;
- [solve_relation_wd | | | ].
+ [solve_proper | | | ].
-End NBasePropFunct.
+End NBaseProp.
diff --git a/theories/Numbers/Natural/Abstract/NBits.v b/theories/Numbers/Natural/Abstract/NBits.v
new file mode 100644
index 00000000..c66f003e
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NBits.v
@@ -0,0 +1,1463 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import Bool NAxioms NSub NPow NDiv NParity NLog.
+
+(** Derived properties of bitwise operations *)
+
+Module Type NBitsProp
+ (Import A : NAxiomsSig')
+ (Import B : NSubProp A)
+ (Import C : NParityProp A B)
+ (Import D : NPowProp A B C)
+ (Import E : NDivProp A B)
+ (Import F : NLog2Prop A B C D).
+
+Include BoolEqualityFacts A.
+
+Ltac order_nz := try apply pow_nonzero; order'.
+Hint Rewrite div_0_l mod_0_l div_1_r mod_1_r : nz.
+
+(** Some properties of power and division *)
+
+Lemma pow_sub_r : forall a b c, a~=0 -> c<=b -> a^(b-c) == a^b / a^c.
+Proof.
+ intros a b c Ha H.
+ apply div_unique with 0.
+ generalize (pow_nonzero a c Ha) (le_0_l (a^c)); order'.
+ nzsimpl. now rewrite <- pow_add_r, add_comm, sub_add.
+Qed.
+
+Lemma pow_div_l : forall a b c, b~=0 -> a mod b == 0 ->
+ (a/b)^c == a^c / b^c.
+Proof.
+ intros a b c Hb H.
+ apply div_unique with 0.
+ generalize (pow_nonzero b c Hb) (le_0_l (b^c)); order'.
+ nzsimpl. rewrite <- pow_mul_l. f_equiv. now apply div_exact.
+Qed.
+
+(** An injection from bits [true] and [false] to numbers 1 and 0.
+ We declare it as a (local) coercion for shorter statements. *)
+
+Definition b2n (b:bool) := if b then 1 else 0.
+Local Coercion b2n : bool >-> t.
+
+Instance b2n_proper : Proper (Logic.eq ==> eq) b2n.
+Proof. solve_proper. Qed.
+
+Lemma exists_div2 a : exists a' (b:bool), a == 2*a' + b.
+Proof.
+ elim (Even_or_Odd a); [intros (a',H)| intros (a',H)].
+ exists a'. exists false. now nzsimpl.
+ exists a'. exists true. now simpl.
+Qed.
+
+(** We can compact [testbit_odd_0] [testbit_even_0]
+ [testbit_even_succ] [testbit_odd_succ] in only two lemmas. *)
+
+Lemma testbit_0_r a (b:bool) : testbit (2*a+b) 0 = b.
+Proof.
+ destruct b; simpl; rewrite ?add_0_r.
+ apply testbit_odd_0.
+ apply testbit_even_0.
+Qed.
+
+Lemma testbit_succ_r a (b:bool) n :
+ testbit (2*a+b) (succ n) = testbit a n.
+Proof.
+ destruct b; simpl; rewrite ?add_0_r.
+ apply testbit_odd_succ, le_0_l.
+ apply testbit_even_succ, le_0_l.
+Qed.
+
+(** Alternative caracterisations of [testbit] *)
+
+(** This concise equation could have been taken as specification
+ for testbit in the interface, but it would have been hard to
+ implement with little initial knowledge about div and mod *)
+
+Lemma testbit_spec' a n : a.[n] == (a / 2^n) mod 2.
+Proof.
+ revert a. induct n.
+ intros a. nzsimpl.
+ destruct (exists_div2 a) as (a' & b & H). rewrite H at 1.
+ rewrite testbit_0_r. apply mod_unique with a'; trivial.
+ destruct b; order'.
+ intros n IH a.
+ destruct (exists_div2 a) as (a' & b & H). rewrite H at 1.
+ rewrite testbit_succ_r, IH. f_equiv.
+ rewrite pow_succ_r', <- div_div by order_nz. f_equiv.
+ apply div_unique with b; trivial.
+ destruct b; order'.
+Qed.
+
+(** This caracterisation that uses only basic operations and
+ power was initially taken as specification for testbit.
+ We describe [a] as having a low part and a high part, with
+ the corresponding bit in the middle. This caracterisation
+ is moderatly complex to implement, but also moderately
+ usable... *)
+
+Lemma testbit_spec a n :
+ exists l h, 0<=l<2^n /\ a == l + (a.[n] + 2*h)*2^n.
+Proof.
+ exists (a mod 2^n). exists (a / 2^n / 2). split.
+ split; [apply le_0_l | apply mod_upper_bound; order_nz].
+ rewrite add_comm, mul_comm, (add_comm a.[n]).
+ rewrite (div_mod a (2^n)) at 1 by order_nz. do 2 f_equiv.
+ rewrite testbit_spec'. apply div_mod. order'.
+Qed.
+
+Lemma testbit_true : forall a n,
+ a.[n] = true <-> (a / 2^n) mod 2 == 1.
+Proof.
+ intros a n.
+ rewrite <- testbit_spec'; destruct a.[n]; split; simpl; now try order'.
+Qed.
+
+Lemma testbit_false : forall a n,
+ a.[n] = false <-> (a / 2^n) mod 2 == 0.
+Proof.
+ intros a n.
+ rewrite <- testbit_spec'; destruct a.[n]; split; simpl; now try order'.
+Qed.
+
+Lemma testbit_eqb : forall a n,
+ a.[n] = eqb ((a / 2^n) mod 2) 1.
+Proof.
+ intros a n.
+ apply eq_true_iff_eq. now rewrite testbit_true, eqb_eq.
+Qed.
+
+(** Results about the injection [b2n] *)
+
+Lemma b2n_inj : forall (a0 b0:bool), a0 == b0 -> a0 = b0.
+Proof.
+ intros [|] [|]; simpl; trivial; order'.
+Qed.
+
+Lemma add_b2n_double_div2 : forall (a0:bool) a, (a0+2*a)/2 == a.
+Proof.
+ intros a0 a. rewrite mul_comm, div_add by order'.
+ now rewrite div_small, add_0_l by (destruct a0; order').
+Qed.
+
+Lemma add_b2n_double_bit0 : forall (a0:bool) a, (a0+2*a).[0] = a0.
+Proof.
+ intros a0 a. apply b2n_inj.
+ rewrite testbit_spec'. nzsimpl. rewrite mul_comm, mod_add by order'.
+ now rewrite mod_small by (destruct a0; order').
+Qed.
+
+Lemma b2n_div2 : forall (a0:bool), a0/2 == 0.
+Proof.
+ intros a0. rewrite <- (add_b2n_double_div2 a0 0). now nzsimpl.
+Qed.
+
+Lemma b2n_bit0 : forall (a0:bool), a0.[0] = a0.
+Proof.
+ intros a0. rewrite <- (add_b2n_double_bit0 a0 0) at 2. now nzsimpl.
+Qed.
+
+(** The specification of testbit by low and high parts is complete *)
+
+Lemma testbit_unique : forall a n (a0:bool) l h,
+ l<2^n -> a == l + (a0 + 2*h)*2^n -> a.[n] = a0.
+Proof.
+ intros a n a0 l h Hl EQ.
+ apply b2n_inj. rewrite testbit_spec' by trivial.
+ symmetry. apply mod_unique with h. destruct a0; simpl; order'.
+ symmetry. apply div_unique with l; trivial.
+ now rewrite add_comm, (add_comm _ a0), mul_comm.
+Qed.
+
+(** All bits of number 0 are 0 *)
+
+Lemma bits_0 : forall n, 0.[n] = false.
+Proof.
+ intros n. apply testbit_false. nzsimpl; order_nz.
+Qed.
+
+(** Various ways to refer to the lowest bit of a number *)
+
+Lemma bit0_odd : forall a, a.[0] = odd a.
+Proof.
+ intros. symmetry.
+ destruct (exists_div2 a) as (a' & b & EQ).
+ rewrite EQ, testbit_0_r, add_comm, odd_add_mul_2.
+ destruct b; simpl; apply odd_1 || apply odd_0.
+Qed.
+
+Lemma bit0_eqb : forall a, a.[0] = eqb (a mod 2) 1.
+Proof.
+ intros a. rewrite testbit_eqb. now nzsimpl.
+Qed.
+
+Lemma bit0_mod : forall a, a.[0] == a mod 2.
+Proof.
+ intros a. rewrite testbit_spec'. now nzsimpl.
+Qed.
+
+(** Hence testing a bit is equivalent to shifting and testing parity *)
+
+Lemma testbit_odd : forall a n, a.[n] = odd (a>>n).
+Proof.
+ intros. now rewrite <- bit0_odd, shiftr_spec, add_0_l.
+Qed.
+
+(** [log2] gives the highest nonzero bit *)
+
+Lemma bit_log2 : forall a, a~=0 -> a.[log2 a] = true.
+Proof.
+ intros a Ha.
+ assert (Ha' : 0 < a) by (generalize (le_0_l a); order).
+ destruct (log2_spec_alt a Ha') as (r & EQ & (_,Hr)).
+ rewrite EQ at 1.
+ rewrite testbit_true, add_comm.
+ rewrite <- (mul_1_l (2^log2 a)) at 1.
+ rewrite div_add by order_nz.
+ rewrite div_small by trivial.
+ rewrite add_0_l. apply mod_small. order'.
+Qed.
+
+Lemma bits_above_log2 : forall a n, log2 a < n ->
+ a.[n] = false.
+Proof.
+ intros a n H.
+ rewrite testbit_false.
+ rewrite div_small. nzsimpl; order'.
+ apply log2_lt_cancel. rewrite log2_pow2; trivial using le_0_l.
+Qed.
+
+(** Hence the number of bits of [a] is [1+log2 a]
+ (see [Psize] and [Psize_pos]).
+*)
+
+(** Testing bits after division or multiplication by a power of two *)
+
+Lemma div2_bits : forall a n, (a/2).[n] = a.[S n].
+Proof.
+ intros. apply eq_true_iff_eq.
+ rewrite 2 testbit_true.
+ rewrite pow_succ_r by apply le_0_l.
+ now rewrite div_div by order_nz.
+Qed.
+
+Lemma div_pow2_bits : forall a n m, (a/2^n).[m] = a.[m+n].
+Proof.
+ intros a n. revert a. induct n.
+ intros a m. now nzsimpl.
+ intros n IH a m. nzsimpl; try apply le_0_l.
+ rewrite <- div_div by order_nz.
+ now rewrite IH, div2_bits.
+Qed.
+
+Lemma double_bits_succ : forall a n, (2*a).[S n] = a.[n].
+Proof.
+ intros. rewrite <- div2_bits. now rewrite mul_comm, div_mul by order'.
+Qed.
+
+Lemma mul_pow2_bits_add : forall a n m, (a*2^n).[m+n] = a.[m].
+Proof.
+ intros. rewrite <- div_pow2_bits. now rewrite div_mul by order_nz.
+Qed.
+
+Lemma mul_pow2_bits_high : forall a n m, n<=m -> (a*2^n).[m] = a.[m-n].
+Proof.
+ intros.
+ rewrite <- (sub_add n m) at 1 by order'.
+ now rewrite mul_pow2_bits_add.
+Qed.
+
+Lemma mul_pow2_bits_low : forall a n m, m<n -> (a*2^n).[m] = false.
+Proof.
+ intros. apply testbit_false.
+ rewrite <- (sub_add m n) by order'. rewrite pow_add_r, mul_assoc.
+ rewrite div_mul by order_nz.
+ rewrite <- (succ_pred (n-m)). rewrite pow_succ_r.
+ now rewrite (mul_comm 2), mul_assoc, mod_mul by order'.
+ apply lt_le_pred.
+ apply sub_gt in H. generalize (le_0_l (n-m)); order.
+ now apply sub_gt.
+Qed.
+
+(** Selecting the low part of a number can be done by a modulo *)
+
+Lemma mod_pow2_bits_high : forall a n m, n<=m ->
+ (a mod 2^n).[m] = false.
+Proof.
+ intros a n m H.
+ destruct (eq_0_gt_0_cases (a mod 2^n)) as [EQ|LT].
+ now rewrite EQ, bits_0.
+ apply bits_above_log2.
+ apply lt_le_trans with n; trivial.
+ apply log2_lt_pow2; trivial.
+ apply mod_upper_bound; order_nz.
+Qed.
+
+Lemma mod_pow2_bits_low : forall a n m, m<n ->
+ (a mod 2^n).[m] = a.[m].
+Proof.
+ intros a n m H.
+ rewrite testbit_eqb.
+ rewrite <- (mod_add _ (2^(P (n-m))*(a/2^n))) by order'.
+ rewrite <- div_add by order_nz.
+ rewrite (mul_comm _ 2), mul_assoc, <- pow_succ_r', succ_pred
+ by now apply sub_gt.
+ rewrite mul_comm, mul_assoc, <- pow_add_r, (add_comm m), sub_add
+ by order.
+ rewrite add_comm, <- div_mod by order_nz.
+ symmetry. apply testbit_eqb.
+Qed.
+
+(** We now prove that having the same bits implies equality.
+ For that we use a notion of equality over functional
+ streams of bits. *)
+
+Definition eqf (f g:t -> bool) := forall n:t, f n = g n.
+
+Instance eqf_equiv : Equivalence eqf.
+Proof.
+ split; congruence.
+Qed.
+
+Local Infix "===" := eqf (at level 70, no associativity).
+
+Instance testbit_eqf : Proper (eq==>eqf) testbit.
+Proof.
+ intros a a' Ha n. now rewrite Ha.
+Qed.
+
+(** Only zero corresponds to the always-false stream. *)
+
+Lemma bits_inj_0 :
+ forall a, (forall n, a.[n] = false) -> a == 0.
+Proof.
+ intros a H. destruct (eq_decidable a 0) as [EQ|NEQ]; trivial.
+ apply bit_log2 in NEQ. now rewrite H in NEQ.
+Qed.
+
+(** If two numbers produce the same stream of bits, they are equal. *)
+
+Lemma bits_inj : forall a b, testbit a === testbit b -> a == b.
+Proof.
+ intros a. pattern a.
+ apply strong_right_induction with 0;[solve_proper|clear a|apply le_0_l].
+ intros a _ IH b H.
+ destruct (eq_0_gt_0_cases a) as [EQ|LT].
+ rewrite EQ in H |- *. symmetry. apply bits_inj_0.
+ intros n. now rewrite <- H, bits_0.
+ rewrite (div_mod a 2), (div_mod b 2) by order'.
+ f_equiv; [ | now rewrite <- 2 bit0_mod, H].
+ f_equiv.
+ apply IH; trivial using le_0_l.
+ apply div_lt; order'.
+ intro n. rewrite 2 div2_bits. apply H.
+Qed.
+
+Lemma bits_inj_iff : forall a b, testbit a === testbit b <-> a == b.
+Proof.
+ split. apply bits_inj. intros EQ; now rewrite EQ.
+Qed.
+
+Hint Rewrite lxor_spec lor_spec land_spec ldiff_spec bits_0 : bitwise.
+
+Ltac bitwise := apply bits_inj; intros ?m; autorewrite with bitwise.
+
+(** The streams of bits that correspond to a natural numbers are
+ exactly the ones that are always 0 after some point *)
+
+Lemma are_bits : forall (f:t->bool), Proper (eq==>Logic.eq) f ->
+ ((exists n, f === testbit n) <->
+ (exists k, forall m, k<=m -> f m = false)).
+Proof.
+ intros f Hf. split.
+ intros (a,H).
+ exists (S (log2 a)). intros m Hm. apply le_succ_l in Hm.
+ rewrite H, bits_above_log2; trivial using lt_succ_diag_r.
+ intros (k,Hk).
+ revert f Hf Hk. induct k.
+ intros f Hf H0.
+ exists 0. intros m. rewrite bits_0, H0; trivial. apply le_0_l.
+ intros k IH f Hf Hk.
+ destruct (IH (fun m => f (S m))) as (n, Hn).
+ solve_proper.
+ intros m Hm. apply Hk. now rewrite <- succ_le_mono.
+ exists (f 0 + 2*n). intros m.
+ destruct (zero_or_succ m) as [Hm|(m', Hm)]; rewrite Hm.
+ symmetry. apply add_b2n_double_bit0.
+ rewrite Hn, <- div2_bits.
+ rewrite mul_comm, div_add, b2n_div2, add_0_l; trivial. order'.
+Qed.
+
+(** Properties of shifts *)
+
+Lemma shiftr_spec' : forall a n m, (a >> n).[m] = a.[m+n].
+Proof.
+ intros. apply shiftr_spec. apply le_0_l.
+Qed.
+
+Lemma shiftl_spec_high' : forall a n m, n<=m -> (a << n).[m] = a.[m-n].
+Proof.
+ intros. apply shiftl_spec_high; trivial. apply le_0_l.
+Qed.
+
+Lemma shiftr_div_pow2 : forall a n, a >> n == a / 2^n.
+Proof.
+ intros. bitwise. rewrite shiftr_spec'.
+ symmetry. apply div_pow2_bits.
+Qed.
+
+Lemma shiftl_mul_pow2 : forall a n, a << n == a * 2^n.
+Proof.
+ intros. bitwise.
+ destruct (le_gt_cases n m) as [H|H].
+ now rewrite shiftl_spec_high', mul_pow2_bits_high.
+ now rewrite shiftl_spec_low, mul_pow2_bits_low.
+Qed.
+
+Lemma shiftl_spec_alt : forall a n m, (a << n).[m+n] = a.[m].
+Proof.
+ intros. now rewrite shiftl_mul_pow2, mul_pow2_bits_add.
+Qed.
+
+Instance shiftr_wd : Proper (eq==>eq==>eq) shiftr.
+Proof.
+ intros a a' Ha b b' Hb. now rewrite 2 shiftr_div_pow2, Ha, Hb.
+Qed.
+
+Instance shiftl_wd : Proper (eq==>eq==>eq) shiftl.
+Proof.
+ intros a a' Ha b b' Hb. now rewrite 2 shiftl_mul_pow2, Ha, Hb.
+Qed.
+
+Lemma shiftl_shiftl : forall a n m,
+ (a << n) << m == a << (n+m).
+Proof.
+ intros. now rewrite !shiftl_mul_pow2, pow_add_r, mul_assoc.
+Qed.
+
+Lemma shiftr_shiftr : forall a n m,
+ (a >> n) >> m == a >> (n+m).
+Proof.
+ intros.
+ now rewrite !shiftr_div_pow2, pow_add_r, div_div by order_nz.
+Qed.
+
+Lemma shiftr_shiftl_l : forall a n m, m<=n ->
+ (a << n) >> m == a << (n-m).
+Proof.
+ intros.
+ rewrite shiftr_div_pow2, !shiftl_mul_pow2.
+ rewrite <- (sub_add m n) at 1 by trivial.
+ now rewrite pow_add_r, mul_assoc, div_mul by order_nz.
+Qed.
+
+Lemma shiftr_shiftl_r : forall a n m, n<=m ->
+ (a << n) >> m == a >> (m-n).
+Proof.
+ intros.
+ rewrite !shiftr_div_pow2, shiftl_mul_pow2.
+ rewrite <- (sub_add n m) at 1 by trivial.
+ rewrite pow_add_r, (mul_comm (2^(m-n))).
+ now rewrite <- div_div, div_mul by order_nz.
+Qed.
+
+(** shifts and constants *)
+
+Lemma shiftl_1_l : forall n, 1 << n == 2^n.
+Proof.
+ intros. now rewrite shiftl_mul_pow2, mul_1_l.
+Qed.
+
+Lemma shiftl_0_r : forall a, a << 0 == a.
+Proof.
+ intros. rewrite shiftl_mul_pow2. now nzsimpl.
+Qed.
+
+Lemma shiftr_0_r : forall a, a >> 0 == a.
+Proof.
+ intros. rewrite shiftr_div_pow2. now nzsimpl.
+Qed.
+
+Lemma shiftl_0_l : forall n, 0 << n == 0.
+Proof.
+ intros. rewrite shiftl_mul_pow2. now nzsimpl.
+Qed.
+
+Lemma shiftr_0_l : forall n, 0 >> n == 0.
+Proof.
+ intros. rewrite shiftr_div_pow2. nzsimpl; order_nz.
+Qed.
+
+Lemma shiftl_eq_0_iff : forall a n, a << n == 0 <-> a == 0.
+Proof.
+ intros a n. rewrite shiftl_mul_pow2. rewrite eq_mul_0. split.
+ intros [H | H]; trivial. contradict H; order_nz.
+ intros H. now left.
+Qed.
+
+Lemma shiftr_eq_0_iff : forall a n,
+ a >> n == 0 <-> a==0 \/ (0<a /\ log2 a < n).
+Proof.
+ intros a n.
+ rewrite shiftr_div_pow2, div_small_iff by order_nz.
+ destruct (eq_0_gt_0_cases a) as [EQ|LT].
+ rewrite EQ. split. now left. intros _.
+ assert (H : 2~=0) by order'.
+ generalize (pow_nonzero 2 n H) (le_0_l (2^n)); order.
+ rewrite log2_lt_pow2; trivial.
+ split. right; split; trivial. intros [H|[_ H]]; now order.
+Qed.
+
+Lemma shiftr_eq_0 : forall a n, log2 a < n -> a >> n == 0.
+Proof.
+ intros a n H. rewrite shiftr_eq_0_iff.
+ destruct (eq_0_gt_0_cases a) as [EQ|LT]. now left. right; now split.
+Qed.
+
+(** Properties of [div2]. *)
+
+Lemma div2_div : forall a, div2 a == a/2.
+Proof.
+ intros. rewrite div2_spec, shiftr_div_pow2. now nzsimpl.
+Qed.
+
+Instance div2_wd : Proper (eq==>eq) div2.
+Proof.
+ intros a a' Ha. now rewrite 2 div2_div, Ha.
+Qed.
+
+Lemma div2_odd : forall a, a == 2*(div2 a) + odd a.
+Proof.
+ intros a. rewrite div2_div, <- bit0_odd, bit0_mod.
+ apply div_mod. order'.
+Qed.
+
+(** Properties of [lxor] and others, directly deduced
+ from properties of [xorb] and others. *)
+
+Instance lxor_wd : Proper (eq ==> eq ==> eq) lxor.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Instance land_wd : Proper (eq ==> eq ==> eq) land.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Instance lor_wd : Proper (eq ==> eq ==> eq) lor.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Instance ldiff_wd : Proper (eq ==> eq ==> eq) ldiff.
+Proof.
+ intros a a' Ha b b' Hb. bitwise. now rewrite Ha, Hb.
+Qed.
+
+Lemma lxor_eq : forall a a', lxor a a' == 0 -> a == a'.
+Proof.
+ intros a a' H. bitwise. apply xorb_eq.
+ now rewrite <- lxor_spec, H, bits_0.
+Qed.
+
+Lemma lxor_nilpotent : forall a, lxor a a == 0.
+Proof.
+ intros. bitwise. apply xorb_nilpotent.
+Qed.
+
+Lemma lxor_eq_0_iff : forall a a', lxor a a' == 0 <-> a == a'.
+Proof.
+ split. apply lxor_eq. intros EQ; rewrite EQ; apply lxor_nilpotent.
+Qed.
+
+Lemma lxor_0_l : forall a, lxor 0 a == a.
+Proof.
+ intros. bitwise. apply xorb_false_l.
+Qed.
+
+Lemma lxor_0_r : forall a, lxor a 0 == a.
+Proof.
+ intros. bitwise. apply xorb_false_r.
+Qed.
+
+Lemma lxor_comm : forall a b, lxor a b == lxor b a.
+Proof.
+ intros. bitwise. apply xorb_comm.
+Qed.
+
+Lemma lxor_assoc :
+ forall a b c, lxor (lxor a b) c == lxor a (lxor b c).
+Proof.
+ intros. bitwise. apply xorb_assoc.
+Qed.
+
+Lemma lor_0_l : forall a, lor 0 a == a.
+Proof.
+ intros. bitwise. trivial.
+Qed.
+
+Lemma lor_0_r : forall a, lor a 0 == a.
+Proof.
+ intros. bitwise. apply orb_false_r.
+Qed.
+
+Lemma lor_comm : forall a b, lor a b == lor b a.
+Proof.
+ intros. bitwise. apply orb_comm.
+Qed.
+
+Lemma lor_assoc :
+ forall a b c, lor a (lor b c) == lor (lor a b) c.
+Proof.
+ intros. bitwise. apply orb_assoc.
+Qed.
+
+Lemma lor_diag : forall a, lor a a == a.
+Proof.
+ intros. bitwise. apply orb_diag.
+Qed.
+
+Lemma lor_eq_0_l : forall a b, lor a b == 0 -> a == 0.
+Proof.
+ intros a b H. bitwise.
+ apply (orb_false_iff a.[m] b.[m]).
+ now rewrite <- lor_spec, H, bits_0.
+Qed.
+
+Lemma lor_eq_0_iff : forall a b, lor a b == 0 <-> a == 0 /\ b == 0.
+Proof.
+ intros a b. split.
+ split. now apply lor_eq_0_l in H.
+ rewrite lor_comm in H. now apply lor_eq_0_l in H.
+ intros (EQ,EQ'). now rewrite EQ, lor_0_l.
+Qed.
+
+Lemma land_0_l : forall a, land 0 a == 0.
+Proof.
+ intros. bitwise. trivial.
+Qed.
+
+Lemma land_0_r : forall a, land a 0 == 0.
+Proof.
+ intros. bitwise. apply andb_false_r.
+Qed.
+
+Lemma land_comm : forall a b, land a b == land b a.
+Proof.
+ intros. bitwise. apply andb_comm.
+Qed.
+
+Lemma land_assoc :
+ forall a b c, land a (land b c) == land (land a b) c.
+Proof.
+ intros. bitwise. apply andb_assoc.
+Qed.
+
+Lemma land_diag : forall a, land a a == a.
+Proof.
+ intros. bitwise. apply andb_diag.
+Qed.
+
+Lemma ldiff_0_l : forall a, ldiff 0 a == 0.
+Proof.
+ intros. bitwise. trivial.
+Qed.
+
+Lemma ldiff_0_r : forall a, ldiff a 0 == a.
+Proof.
+ intros. bitwise. now rewrite andb_true_r.
+Qed.
+
+Lemma ldiff_diag : forall a, ldiff a a == 0.
+Proof.
+ intros. bitwise. apply andb_negb_r.
+Qed.
+
+Lemma lor_land_distr_l : forall a b c,
+ lor (land a b) c == land (lor a c) (lor b c).
+Proof.
+ intros. bitwise. apply orb_andb_distrib_l.
+Qed.
+
+Lemma lor_land_distr_r : forall a b c,
+ lor a (land b c) == land (lor a b) (lor a c).
+Proof.
+ intros. bitwise. apply orb_andb_distrib_r.
+Qed.
+
+Lemma land_lor_distr_l : forall a b c,
+ land (lor a b) c == lor (land a c) (land b c).
+Proof.
+ intros. bitwise. apply andb_orb_distrib_l.
+Qed.
+
+Lemma land_lor_distr_r : forall a b c,
+ land a (lor b c) == lor (land a b) (land a c).
+Proof.
+ intros. bitwise. apply andb_orb_distrib_r.
+Qed.
+
+Lemma ldiff_ldiff_l : forall a b c,
+ ldiff (ldiff a b) c == ldiff a (lor b c).
+Proof.
+ intros. bitwise. now rewrite negb_orb, andb_assoc.
+Qed.
+
+Lemma lor_ldiff_and : forall a b,
+ lor (ldiff a b) (land a b) == a.
+Proof.
+ intros. bitwise.
+ now rewrite <- andb_orb_distrib_r, orb_comm, orb_negb_r, andb_true_r.
+Qed.
+
+Lemma land_ldiff : forall a b,
+ land (ldiff a b) b == 0.
+Proof.
+ intros. bitwise.
+ now rewrite <-andb_assoc, (andb_comm (negb _)), andb_negb_r, andb_false_r.
+Qed.
+
+(** Properties of [setbit] and [clearbit] *)
+
+Definition setbit a n := lor a (1<<n).
+Definition clearbit a n := ldiff a (1<<n).
+
+Lemma setbit_spec' : forall a n, setbit a n == lor a (2^n).
+Proof.
+ intros. unfold setbit. now rewrite shiftl_1_l.
+Qed.
+
+Lemma clearbit_spec' : forall a n, clearbit a n == ldiff a (2^n).
+Proof.
+ intros. unfold clearbit. now rewrite shiftl_1_l.
+Qed.
+
+Instance setbit_wd : Proper (eq==>eq==>eq) setbit.
+Proof. unfold setbit. solve_proper. Qed.
+
+Instance clearbit_wd : Proper (eq==>eq==>eq) clearbit.
+Proof. unfold clearbit. solve_proper. Qed.
+
+Lemma pow2_bits_true : forall n, (2^n).[n] = true.
+Proof.
+ intros. rewrite <- (mul_1_l (2^n)). rewrite <- (add_0_l n) at 2.
+ now rewrite mul_pow2_bits_add, bit0_odd, odd_1.
+Qed.
+
+Lemma pow2_bits_false : forall n m, n~=m -> (2^n).[m] = false.
+Proof.
+ intros.
+ rewrite <- (mul_1_l (2^n)).
+ destruct (le_gt_cases n m).
+ rewrite mul_pow2_bits_high; trivial.
+ rewrite <- (succ_pred (m-n)) by (apply sub_gt; order).
+ now rewrite <- div2_bits, div_small, bits_0 by order'.
+ rewrite mul_pow2_bits_low; trivial.
+Qed.
+
+Lemma pow2_bits_eqb : forall n m, (2^n).[m] = eqb n m.
+Proof.
+ intros. apply eq_true_iff_eq. rewrite eqb_eq. split.
+ destruct (eq_decidable n m) as [H|H]. trivial.
+ now rewrite (pow2_bits_false _ _ H).
+ intros EQ. rewrite EQ. apply pow2_bits_true.
+Qed.
+
+Lemma setbit_eqb : forall a n m,
+ (setbit a n).[m] = eqb n m || a.[m].
+Proof.
+ intros. now rewrite setbit_spec', lor_spec, pow2_bits_eqb, orb_comm.
+Qed.
+
+Lemma setbit_iff : forall a n m,
+ (setbit a n).[m] = true <-> n==m \/ a.[m] = true.
+Proof.
+ intros. now rewrite setbit_eqb, orb_true_iff, eqb_eq.
+Qed.
+
+Lemma setbit_eq : forall a n, (setbit a n).[n] = true.
+Proof.
+ intros. apply setbit_iff. now left.
+Qed.
+
+Lemma setbit_neq : forall a n m, n~=m ->
+ (setbit a n).[m] = a.[m].
+Proof.
+ intros a n m H. rewrite setbit_eqb.
+ rewrite <- eqb_eq in H. apply not_true_is_false in H. now rewrite H.
+Qed.
+
+Lemma clearbit_eqb : forall a n m,
+ (clearbit a n).[m] = a.[m] && negb (eqb n m).
+Proof.
+ intros. now rewrite clearbit_spec', ldiff_spec, pow2_bits_eqb.
+Qed.
+
+Lemma clearbit_iff : forall a n m,
+ (clearbit a n).[m] = true <-> a.[m] = true /\ n~=m.
+Proof.
+ intros. rewrite clearbit_eqb, andb_true_iff, <- eqb_eq.
+ now rewrite negb_true_iff, not_true_iff_false.
+Qed.
+
+Lemma clearbit_eq : forall a n, (clearbit a n).[n] = false.
+Proof.
+ intros. rewrite clearbit_eqb, (proj2 (eqb_eq _ _) (eq_refl n)).
+ apply andb_false_r.
+Qed.
+
+Lemma clearbit_neq : forall a n m, n~=m ->
+ (clearbit a n).[m] = a.[m].
+Proof.
+ intros a n m H. rewrite clearbit_eqb.
+ rewrite <- eqb_eq in H. apply not_true_is_false in H. rewrite H.
+ apply andb_true_r.
+Qed.
+
+(** Shifts of bitwise operations *)
+
+Lemma shiftl_lxor : forall a b n,
+ (lxor a b) << n == lxor (a << n) (b << n).
+Proof.
+ intros. bitwise.
+ destruct (le_gt_cases n m).
+ now rewrite !shiftl_spec_high', lxor_spec.
+ now rewrite !shiftl_spec_low.
+Qed.
+
+Lemma shiftr_lxor : forall a b n,
+ (lxor a b) >> n == lxor (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec', lxor_spec.
+Qed.
+
+Lemma shiftl_land : forall a b n,
+ (land a b) << n == land (a << n) (b << n).
+Proof.
+ intros. bitwise.
+ destruct (le_gt_cases n m).
+ now rewrite !shiftl_spec_high', land_spec.
+ now rewrite !shiftl_spec_low.
+Qed.
+
+Lemma shiftr_land : forall a b n,
+ (land a b) >> n == land (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec', land_spec.
+Qed.
+
+Lemma shiftl_lor : forall a b n,
+ (lor a b) << n == lor (a << n) (b << n).
+Proof.
+ intros. bitwise.
+ destruct (le_gt_cases n m).
+ now rewrite !shiftl_spec_high', lor_spec.
+ now rewrite !shiftl_spec_low.
+Qed.
+
+Lemma shiftr_lor : forall a b n,
+ (lor a b) >> n == lor (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec', lor_spec.
+Qed.
+
+Lemma shiftl_ldiff : forall a b n,
+ (ldiff a b) << n == ldiff (a << n) (b << n).
+Proof.
+ intros. bitwise.
+ destruct (le_gt_cases n m).
+ now rewrite !shiftl_spec_high', ldiff_spec.
+ now rewrite !shiftl_spec_low.
+Qed.
+
+Lemma shiftr_ldiff : forall a b n,
+ (ldiff a b) >> n == ldiff (a >> n) (b >> n).
+Proof.
+ intros. bitwise. now rewrite !shiftr_spec', ldiff_spec.
+Qed.
+
+(** We cannot have a function complementing all bits of a number,
+ otherwise it would have an infinity of bit 1. Nonetheless,
+ we can design a bounded complement *)
+
+Definition ones n := P (1 << n).
+
+Definition lnot a n := lxor a (ones n).
+
+Instance ones_wd : Proper (eq==>eq) ones.
+Proof. unfold ones. solve_proper. Qed.
+
+Instance lnot_wd : Proper (eq==>eq==>eq) lnot.
+Proof. unfold lnot. solve_proper. Qed.
+
+Lemma ones_equiv : forall n, ones n == P (2^n).
+Proof.
+ intros; unfold ones; now rewrite shiftl_1_l.
+Qed.
+
+Lemma ones_add : forall n m, ones (m+n) == 2^m * ones n + ones m.
+Proof.
+ intros n m. rewrite !ones_equiv.
+ rewrite <- !sub_1_r, mul_sub_distr_l, mul_1_r, <- pow_add_r.
+ rewrite add_sub_assoc, sub_add. reflexivity.
+ apply pow_le_mono_r. order'.
+ rewrite <- (add_0_r m) at 1. apply add_le_mono_l, le_0_l.
+ rewrite <- (pow_0_r 2). apply pow_le_mono_r. order'. apply le_0_l.
+Qed.
+
+Lemma ones_div_pow2 : forall n m, m<=n -> ones n / 2^m == ones (n-m).
+Proof.
+ intros n m H. symmetry. apply div_unique with (ones m).
+ rewrite ones_equiv.
+ apply le_succ_l. rewrite succ_pred; order_nz.
+ rewrite <- (sub_add m n H) at 1. rewrite (add_comm _ m).
+ apply ones_add.
+Qed.
+
+Lemma ones_mod_pow2 : forall n m, m<=n -> (ones n) mod (2^m) == ones m.
+Proof.
+ intros n m H. symmetry. apply mod_unique with (ones (n-m)).
+ rewrite ones_equiv.
+ apply le_succ_l. rewrite succ_pred; order_nz.
+ rewrite <- (sub_add m n H) at 1. rewrite (add_comm _ m).
+ apply ones_add.
+Qed.
+
+Lemma ones_spec_low : forall n m, m<n -> (ones n).[m] = true.
+Proof.
+ intros. apply testbit_true. rewrite ones_div_pow2 by order.
+ rewrite <- (pow_1_r 2). rewrite ones_mod_pow2.
+ rewrite ones_equiv. now nzsimpl'.
+ apply le_add_le_sub_r. nzsimpl. now apply le_succ_l.
+Qed.
+
+Lemma ones_spec_high : forall n m, n<=m -> (ones n).[m] = false.
+Proof.
+ intros.
+ destruct (eq_0_gt_0_cases n) as [EQ|LT]; rewrite ones_equiv.
+ now rewrite EQ, pow_0_r, one_succ, pred_succ, bits_0.
+ apply bits_above_log2.
+ rewrite log2_pred_pow2; trivial. rewrite <-le_succ_l, succ_pred; order.
+Qed.
+
+Lemma ones_spec_iff : forall n m, (ones n).[m] = true <-> m<n.
+Proof.
+ intros. split. intros H.
+ apply lt_nge. intro H'. apply ones_spec_high in H'.
+ rewrite H in H'; discriminate.
+ apply ones_spec_low.
+Qed.
+
+Lemma lnot_spec_low : forall a n m, m<n ->
+ (lnot a n).[m] = negb a.[m].
+Proof.
+ intros. unfold lnot. now rewrite lxor_spec, ones_spec_low.
+Qed.
+
+Lemma lnot_spec_high : forall a n m, n<=m ->
+ (lnot a n).[m] = a.[m].
+Proof.
+ intros. unfold lnot. now rewrite lxor_spec, ones_spec_high, xorb_false_r.
+Qed.
+
+Lemma lnot_involutive : forall a n, lnot (lnot a n) n == a.
+Proof.
+ intros a n. bitwise.
+ destruct (le_gt_cases n m).
+ now rewrite 2 lnot_spec_high.
+ now rewrite 2 lnot_spec_low, negb_involutive.
+Qed.
+
+Lemma lnot_0_l : forall n, lnot 0 n == ones n.
+Proof.
+ intros. unfold lnot. apply lxor_0_l.
+Qed.
+
+Lemma lnot_ones : forall n, lnot (ones n) n == 0.
+Proof.
+ intros. unfold lnot. apply lxor_nilpotent.
+Qed.
+
+(** Bounded complement and other operations *)
+
+Lemma lor_ones_low : forall a n, log2 a < n ->
+ lor a (ones n) == ones n.
+Proof.
+ intros a n H. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ now rewrite ones_spec_low, orb_true_r.
+Qed.
+
+Lemma land_ones : forall a n, land a (ones n) == a mod 2^n.
+Proof.
+ intros a n. bitwise. destruct (le_gt_cases n m).
+ now rewrite ones_spec_high, mod_pow2_bits_high, andb_false_r.
+ now rewrite ones_spec_low, mod_pow2_bits_low, andb_true_r.
+Qed.
+
+Lemma land_ones_low : forall a n, log2 a < n ->
+ land a (ones n) == a.
+Proof.
+ intros; rewrite land_ones. apply mod_small.
+ apply log2_lt_cancel. rewrite log2_pow2; trivial using le_0_l.
+Qed.
+
+Lemma ldiff_ones_r : forall a n,
+ ldiff a (ones n) == (a >> n) << n.
+Proof.
+ intros a n. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, shiftl_spec_high', shiftr_spec'; trivial.
+ rewrite sub_add; trivial. apply andb_true_r.
+ now rewrite ones_spec_low, shiftl_spec_low, andb_false_r.
+Qed.
+
+Lemma ldiff_ones_r_low : forall a n, log2 a < n ->
+ ldiff a (ones n) == 0.
+Proof.
+ intros a n H. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ now rewrite ones_spec_low, andb_false_r.
+Qed.
+
+Lemma ldiff_ones_l_low : forall a n, log2 a < n ->
+ ldiff (ones n) a == lnot a n.
+Proof.
+ intros a n H. bitwise. destruct (le_gt_cases n m).
+ rewrite ones_spec_high, lnot_spec_high, bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ now rewrite ones_spec_low, lnot_spec_low.
+Qed.
+
+Lemma lor_lnot_diag : forall a n,
+ lor a (lnot a n) == lor a (ones n).
+Proof.
+ intros a n. bitwise.
+ destruct (le_gt_cases n m).
+ rewrite lnot_spec_high, ones_spec_high; trivial. now destruct a.[m].
+ rewrite lnot_spec_low, ones_spec_low; trivial. now destruct a.[m].
+Qed.
+
+Lemma lor_lnot_diag_low : forall a n, log2 a < n ->
+ lor a (lnot a n) == ones n.
+Proof.
+ intros a n H. now rewrite lor_lnot_diag, lor_ones_low.
+Qed.
+
+Lemma land_lnot_diag : forall a n,
+ land a (lnot a n) == ldiff a (ones n).
+Proof.
+ intros a n. bitwise.
+ destruct (le_gt_cases n m).
+ rewrite lnot_spec_high, ones_spec_high; trivial. now destruct a.[m].
+ rewrite lnot_spec_low, ones_spec_low; trivial. now destruct a.[m].
+Qed.
+
+Lemma land_lnot_diag_low : forall a n, log2 a < n ->
+ land a (lnot a n) == 0.
+Proof.
+ intros. now rewrite land_lnot_diag, ldiff_ones_r_low.
+Qed.
+
+Lemma lnot_lor_low : forall a b n, log2 a < n -> log2 b < n ->
+ lnot (lor a b) n == land (lnot a n) (lnot b n).
+Proof.
+ intros a b n Ha Hb. bitwise. destruct (le_gt_cases n m).
+ rewrite !lnot_spec_high, lor_spec, !bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ now apply lt_le_trans with n.
+ now rewrite !lnot_spec_low, lor_spec, negb_orb.
+Qed.
+
+Lemma lnot_land_low : forall a b n, log2 a < n -> log2 b < n ->
+ lnot (land a b) n == lor (lnot a n) (lnot b n).
+Proof.
+ intros a b n Ha Hb. bitwise. destruct (le_gt_cases n m).
+ rewrite !lnot_spec_high, land_spec, !bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ now apply lt_le_trans with n.
+ now rewrite !lnot_spec_low, land_spec, negb_andb.
+Qed.
+
+Lemma ldiff_land_low : forall a b n, log2 a < n ->
+ ldiff a b == land a (lnot b n).
+Proof.
+ intros a b n Ha. bitwise. destruct (le_gt_cases n m).
+ rewrite (bits_above_log2 a m). trivial.
+ now apply lt_le_trans with n.
+ rewrite !lnot_spec_low; trivial.
+Qed.
+
+Lemma lnot_ldiff_low : forall a b n, log2 a < n -> log2 b < n ->
+ lnot (ldiff a b) n == lor (lnot a n) b.
+Proof.
+ intros a b n Ha Hb. bitwise. destruct (le_gt_cases n m).
+ rewrite !lnot_spec_high, ldiff_spec, !bits_above_log2; trivial.
+ now apply lt_le_trans with n.
+ now apply lt_le_trans with n.
+ now rewrite !lnot_spec_low, ldiff_spec, negb_andb, negb_involutive.
+Qed.
+
+Lemma lxor_lnot_lnot : forall a b n,
+ lxor (lnot a n) (lnot b n) == lxor a b.
+Proof.
+ intros a b n. bitwise. destruct (le_gt_cases n m).
+ rewrite !lnot_spec_high; trivial.
+ rewrite !lnot_spec_low, xorb_negb_negb; trivial.
+Qed.
+
+Lemma lnot_lxor_l : forall a b n,
+ lnot (lxor a b) n == lxor (lnot a n) b.
+Proof.
+ intros a b n. bitwise. destruct (le_gt_cases n m).
+ rewrite !lnot_spec_high, lxor_spec; trivial.
+ rewrite !lnot_spec_low, lxor_spec, negb_xorb_l; trivial.
+Qed.
+
+Lemma lnot_lxor_r : forall a b n,
+ lnot (lxor a b) n == lxor a (lnot b n).
+Proof.
+ intros a b n. bitwise. destruct (le_gt_cases n m).
+ rewrite !lnot_spec_high, lxor_spec; trivial.
+ rewrite !lnot_spec_low, lxor_spec, negb_xorb_r; trivial.
+Qed.
+
+Lemma lxor_lor : forall a b, land a b == 0 ->
+ lxor a b == lor a b.
+Proof.
+ intros a b H. bitwise.
+ assert (a.[m] && b.[m] = false)
+ by now rewrite <- land_spec, H, bits_0.
+ now destruct a.[m], b.[m].
+Qed.
+
+(** Bitwise operations and log2 *)
+
+Lemma log2_bits_unique : forall a n,
+ a.[n] = true ->
+ (forall m, n<m -> a.[m] = false) ->
+ log2 a == n.
+Proof.
+ intros a n H H'.
+ destruct (eq_0_gt_0_cases a) as [Ha|Ha].
+ now rewrite Ha, bits_0 in H.
+ apply le_antisymm; apply le_ngt; intros LT.
+ specialize (H' _ LT). now rewrite bit_log2 in H' by order.
+ now rewrite bits_above_log2 in H by order.
+Qed.
+
+Lemma log2_shiftr : forall a n, log2 (a >> n) == log2 a - n.
+Proof.
+ intros a n.
+ destruct (eq_0_gt_0_cases a) as [Ha|Ha].
+ now rewrite Ha, shiftr_0_l, log2_nonpos, sub_0_l by order.
+ destruct (lt_ge_cases (log2 a) n).
+ rewrite shiftr_eq_0, log2_nonpos by order.
+ symmetry. rewrite sub_0_le; order.
+ apply log2_bits_unique.
+ now rewrite shiftr_spec', sub_add, bit_log2 by order.
+ intros m Hm.
+ rewrite shiftr_spec'; trivial. apply bits_above_log2; try order.
+ now apply lt_sub_lt_add_r.
+Qed.
+
+Lemma log2_shiftl : forall a n, a~=0 -> log2 (a << n) == log2 a + n.
+Proof.
+ intros a n Ha.
+ rewrite shiftl_mul_pow2, add_comm by trivial.
+ apply log2_mul_pow2. generalize (le_0_l a); order. apply le_0_l.
+Qed.
+
+Lemma log2_lor : forall a b,
+ log2 (lor a b) == max (log2 a) (log2 b).
+Proof.
+ assert (AUX : forall a b, a<=b -> log2 (lor a b) == log2 b).
+ intros a b H.
+ destruct (eq_0_gt_0_cases a) as [Ha|Ha]. now rewrite Ha, lor_0_l.
+ apply log2_bits_unique.
+ now rewrite lor_spec, bit_log2, orb_true_r by order.
+ intros m Hm. assert (H' := log2_le_mono _ _ H).
+ now rewrite lor_spec, 2 bits_above_log2 by order.
+ (* main *)
+ intros a b. destruct (le_ge_cases a b) as [H|H].
+ rewrite max_r by now apply log2_le_mono.
+ now apply AUX.
+ rewrite max_l by now apply log2_le_mono.
+ rewrite lor_comm. now apply AUX.
+Qed.
+
+Lemma log2_land : forall a b,
+ log2 (land a b) <= min (log2 a) (log2 b).
+Proof.
+ assert (AUX : forall a b, a<=b -> log2 (land a b) <= log2 a).
+ intros a b H.
+ apply le_ngt. intros H'.
+ destruct (eq_decidable (land a b) 0) as [EQ|NEQ].
+ rewrite EQ in H'. apply log2_lt_cancel in H'. generalize (le_0_l a); order.
+ generalize (bit_log2 (land a b) NEQ).
+ now rewrite land_spec, bits_above_log2.
+ (* main *)
+ intros a b.
+ destruct (le_ge_cases a b) as [H|H].
+ rewrite min_l by now apply log2_le_mono. now apply AUX.
+ rewrite min_r by now apply log2_le_mono. rewrite land_comm. now apply AUX.
+Qed.
+
+Lemma log2_lxor : forall a b,
+ log2 (lxor a b) <= max (log2 a) (log2 b).
+Proof.
+ assert (AUX : forall a b, a<=b -> log2 (lxor a b) <= log2 b).
+ intros a b H.
+ apply le_ngt. intros H'.
+ destruct (eq_decidable (lxor a b) 0) as [EQ|NEQ].
+ rewrite EQ in H'. apply log2_lt_cancel in H'. generalize (le_0_l a); order.
+ generalize (bit_log2 (lxor a b) NEQ).
+ rewrite lxor_spec, 2 bits_above_log2; try order. discriminate.
+ apply le_lt_trans with (log2 b); trivial. now apply log2_le_mono.
+ (* main *)
+ intros a b.
+ destruct (le_ge_cases a b) as [H|H].
+ rewrite max_r by now apply log2_le_mono. now apply AUX.
+ rewrite max_l by now apply log2_le_mono. rewrite lxor_comm. now apply AUX.
+Qed.
+
+(** Bitwise operations and arithmetical operations *)
+
+Local Notation xor3 a b c := (xorb (xorb a b) c).
+Local Notation lxor3 a b c := (lxor (lxor a b) c).
+
+Local Notation nextcarry a b c := ((a&&b) || (c && (a||b))).
+Local Notation lnextcarry a b c := (lor (land a b) (land c (lor a b))).
+
+Lemma add_bit0 : forall a b, (a+b).[0] = xorb a.[0] b.[0].
+Proof.
+ intros. now rewrite !bit0_odd, odd_add.
+Qed.
+
+Lemma add3_bit0 : forall a b c,
+ (a+b+c).[0] = xor3 a.[0] b.[0] c.[0].
+Proof.
+ intros. now rewrite !add_bit0.
+Qed.
+
+Lemma add3_bits_div2 : forall (a0 b0 c0 : bool),
+ (a0 + b0 + c0)/2 == nextcarry a0 b0 c0.
+Proof.
+ assert (H : 1+1 == 2) by now nzsimpl'.
+ intros [|] [|] [|]; simpl; rewrite ?add_0_l, ?add_0_r, ?H;
+ (apply div_same; order') || (apply div_small; order') || idtac.
+ symmetry. apply div_unique with 1. order'. now nzsimpl'.
+Qed.
+
+Lemma add_carry_div2 : forall a b (c0:bool),
+ (a + b + c0)/2 == a/2 + b/2 + nextcarry a.[0] b.[0] c0.
+Proof.
+ intros.
+ rewrite <- add3_bits_div2.
+ rewrite (add_comm ((a/2)+_)).
+ rewrite <- div_add by order'.
+ f_equiv.
+ rewrite <- !div2_div, mul_comm, mul_add_distr_l.
+ rewrite (div2_odd a), <- bit0_odd at 1. fold (b2n a.[0]).
+ rewrite (div2_odd b), <- bit0_odd at 1. fold (b2n b.[0]).
+ rewrite add_shuffle1.
+ rewrite <-(add_assoc _ _ c0). apply add_comm.
+Qed.
+
+(** The main result concerning addition: we express the bits of the sum
+ in term of bits of [a] and [b] and of some carry stream which is also
+ recursively determined by another equation.
+*)
+
+Lemma add_carry_bits : forall a b (c0:bool), exists c,
+ a+b+c0 == lxor3 a b c /\ c/2 == lnextcarry a b c /\ c.[0] = c0.
+Proof.
+ intros a b c0.
+ (* induction over some n such that [a<2^n] and [b<2^n] *)
+ set (n:=max a b).
+ assert (Ha : a<2^n).
+ apply lt_le_trans with (2^a). apply pow_gt_lin_r, lt_1_2.
+ apply pow_le_mono_r. order'. unfold n.
+ destruct (le_ge_cases a b); [rewrite max_r|rewrite max_l]; order'.
+ assert (Hb : b<2^n).
+ apply lt_le_trans with (2^b). apply pow_gt_lin_r, lt_1_2.
+ apply pow_le_mono_r. order'. unfold n.
+ destruct (le_ge_cases a b); [rewrite max_r|rewrite max_l]; order'.
+ clearbody n.
+ revert a b c0 Ha Hb. induct n.
+ (*base*)
+ intros a b c0. rewrite !pow_0_r, !one_succ, !lt_succ_r. intros Ha Hb.
+ exists c0.
+ setoid_replace a with 0 by (generalize (le_0_l a); order').
+ setoid_replace b with 0 by (generalize (le_0_l b); order').
+ rewrite !add_0_l, !lxor_0_l, !lor_0_r, !land_0_r, !lor_0_r.
+ rewrite b2n_div2, b2n_bit0; now repeat split.
+ (*step*)
+ intros n IH a b c0 Ha Hb.
+ set (c1:=nextcarry a.[0] b.[0] c0).
+ destruct (IH (a/2) (b/2) c1) as (c & IH1 & IH2 & Hc); clear IH.
+ apply div_lt_upper_bound; trivial. order'. now rewrite <- pow_succ_r'.
+ apply div_lt_upper_bound; trivial. order'. now rewrite <- pow_succ_r'.
+ exists (c0 + 2*c). repeat split.
+ (* - add *)
+ bitwise.
+ destruct (zero_or_succ m) as [EQ|[m' EQ]]; rewrite EQ; clear EQ.
+ now rewrite add_b2n_double_bit0, add3_bit0, b2n_bit0.
+ rewrite <- !div2_bits, <- 2 lxor_spec.
+ f_equiv.
+ rewrite add_b2n_double_div2, <- IH1. apply add_carry_div2.
+ (* - carry *)
+ rewrite add_b2n_double_div2.
+ bitwise.
+ destruct (zero_or_succ m) as [EQ|[m' EQ]]; rewrite EQ; clear EQ.
+ now rewrite add_b2n_double_bit0.
+ rewrite <- !div2_bits, IH2. autorewrite with bitwise.
+ now rewrite add_b2n_double_div2.
+ (* - carry0 *)
+ apply add_b2n_double_bit0.
+Qed.
+
+(** Particular case : the second bit of an addition *)
+
+Lemma add_bit1 : forall a b,
+ (a+b).[1] = xor3 a.[1] b.[1] (a.[0] && b.[0]).
+Proof.
+ intros a b.
+ destruct (add_carry_bits a b false) as (c & EQ1 & EQ2 & Hc).
+ simpl in EQ1; rewrite add_0_r in EQ1. rewrite EQ1.
+ autorewrite with bitwise. f_equal.
+ rewrite one_succ, <- div2_bits, EQ2.
+ autorewrite with bitwise.
+ rewrite Hc. simpl. apply orb_false_r.
+Qed.
+
+(** In an addition, there will be no carries iff there is
+ no common bits in the numbers to add *)
+
+Lemma nocarry_equiv : forall a b c,
+ c/2 == lnextcarry a b c -> c.[0] = false ->
+ (c == 0 <-> land a b == 0).
+Proof.
+ intros a b c H H'.
+ split. intros EQ; rewrite EQ in *.
+ rewrite div_0_l in H by order'.
+ symmetry in H. now apply lor_eq_0_l in H.
+ intros EQ. rewrite EQ, lor_0_l in H.
+ apply bits_inj_0.
+ induct n. trivial.
+ intros n IH.
+ rewrite <- div2_bits, H.
+ autorewrite with bitwise.
+ now rewrite IH.
+Qed.
+
+(** When there is no common bits, the addition is just a xor *)
+
+Lemma add_nocarry_lxor : forall a b, land a b == 0 ->
+ a+b == lxor a b.
+Proof.
+ intros a b H.
+ destruct (add_carry_bits a b false) as (c & EQ1 & EQ2 & Hc).
+ simpl in EQ1; rewrite add_0_r in EQ1. rewrite EQ1.
+ apply (nocarry_equiv a b c) in H; trivial.
+ rewrite H. now rewrite lxor_0_r.
+Qed.
+
+(** A null [ldiff] implies being smaller *)
+
+Lemma ldiff_le : forall a b, ldiff a b == 0 -> a <= b.
+Proof.
+ cut (forall n a b, a < 2^n -> ldiff a b == 0 -> a <= b).
+ intros H a b. apply (H a), pow_gt_lin_r; order'.
+ induct n.
+ intros a b Ha _. rewrite pow_0_r, one_succ, lt_succ_r in Ha.
+ assert (Ha' : a == 0) by (generalize (le_0_l a); order').
+ rewrite Ha'. apply le_0_l.
+ intros n IH a b Ha H.
+ assert (NEQ : 2 ~= 0) by order'.
+ rewrite (div_mod a 2 NEQ), (div_mod b 2 NEQ).
+ apply add_le_mono.
+ apply mul_le_mono_l.
+ apply IH.
+ apply div_lt_upper_bound; trivial. now rewrite <- pow_succ_r'.
+ rewrite <- (pow_1_r 2), <- 2 shiftr_div_pow2.
+ now rewrite <- shiftr_ldiff, H, shiftr_div_pow2, pow_1_r, div_0_l.
+ rewrite <- 2 bit0_mod.
+ apply bits_inj_iff in H. specialize (H 0).
+ rewrite ldiff_spec, bits_0 in H.
+ destruct a.[0], b.[0]; try discriminate; simpl; order'.
+Qed.
+
+(** Subtraction can be a ldiff when the opposite ldiff is null. *)
+
+Lemma sub_nocarry_ldiff : forall a b, ldiff b a == 0 ->
+ a-b == ldiff a b.
+Proof.
+ intros a b H.
+ apply add_cancel_r with b.
+ rewrite sub_add.
+ symmetry.
+ rewrite add_nocarry_lxor.
+ bitwise.
+ apply bits_inj_iff in H. specialize (H m).
+ rewrite ldiff_spec, bits_0 in H.
+ now destruct a.[m], b.[m].
+ apply land_ldiff.
+ now apply ldiff_le.
+Qed.
+
+(** We can express lnot in term of subtraction *)
+
+Lemma add_lnot_diag_low : forall a n, log2 a < n ->
+ a + lnot a n == ones n.
+Proof.
+ intros a n H.
+ assert (H' := land_lnot_diag_low a n H).
+ rewrite add_nocarry_lxor, lxor_lor by trivial.
+ now apply lor_lnot_diag_low.
+Qed.
+
+Lemma lnot_sub_low : forall a n, log2 a < n ->
+ lnot a n == ones n - a.
+Proof.
+ intros a n H.
+ now rewrite <- (add_lnot_diag_low a n H), add_comm, add_sub.
+Qed.
+
+(** Adding numbers with no common bits cannot lead to a much bigger number *)
+
+Lemma add_nocarry_lt_pow2 : forall a b n, land a b == 0 ->
+ a < 2^n -> b < 2^n -> a+b < 2^n.
+Proof.
+ intros a b n H Ha Hb.
+ rewrite add_nocarry_lxor by trivial.
+ apply div_small_iff. order_nz.
+ rewrite <- shiftr_div_pow2, shiftr_lxor, !shiftr_div_pow2.
+ rewrite 2 div_small by trivial.
+ apply lxor_0_l.
+Qed.
+
+Lemma add_nocarry_mod_lt_pow2 : forall a b n, land a b == 0 ->
+ a mod 2^n + b mod 2^n < 2^n.
+Proof.
+ intros a b n H.
+ apply add_nocarry_lt_pow2.
+ bitwise.
+ destruct (le_gt_cases n m).
+ now rewrite mod_pow2_bits_high.
+ now rewrite !mod_pow2_bits_low, <- land_spec, H, bits_0.
+ apply mod_upper_bound; order_nz.
+ apply mod_upper_bound; order_nz.
+Qed.
+
+End NBitsProp.
diff --git a/theories/Numbers/Natural/Abstract/NDefOps.v b/theories/Numbers/Natural/Abstract/NDefOps.v
index 7b38c148..ad7a9f3a 100644
--- a/theories/Numbers/Natural/Abstract/NDefOps.v
+++ b/theories/Numbers/Natural/Abstract/NDefOps.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,14 +8,41 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NDefOps.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import Bool. (* To get the orb and negb function *)
Require Import RelationPairs.
Require Export NStrongRec.
-Module NdefOpsPropFunct (Import N : NAxiomsSig').
-Include NStrongRecPropFunct N.
+(** In this module, we derive generic implementations of usual operators
+ just via the use of a [recursion] function. *)
+
+Module NdefOpsProp (Import N : NAxiomsRecSig').
+Include NStrongRecProp N.
+
+(** Nullity Test *)
+
+Definition if_zero (A : Type) (a b : A) (n : N.t) : A :=
+ recursion a (fun _ _ => b) n.
+
+Arguments if_zero [A] a b n.
+
+Instance if_zero_wd (A : Type) :
+ Proper (Logic.eq ==> Logic.eq ==> N.eq ==> Logic.eq) (@if_zero A).
+Proof.
+unfold if_zero. (* TODO : solve_proper : SLOW + BUG *)
+f_equiv'.
+Qed.
+
+Theorem if_zero_0 : forall (A : Type) (a b : A), if_zero a b 0 = a.
+Proof.
+unfold if_zero; intros; now rewrite recursion_0.
+Qed.
+
+Theorem if_zero_succ :
+ forall (A : Type) (a b : A) (n : N.t), if_zero a b (S n) = b.
+Proof.
+intros; unfold if_zero.
+now rewrite recursion_succ.
+Qed.
(*****************************************************)
(** Addition *)
@@ -24,17 +51,9 @@ Definition def_add (x y : N.t) := recursion y (fun _ => S) x.
Local Infix "+++" := def_add (at level 50, left associativity).
-Instance def_add_prewd : Proper (N.eq==>N.eq==>N.eq) (fun _ => S).
-Proof.
-intros _ _ _ p p' Epp'; now rewrite Epp'.
-Qed.
-
Instance def_add_wd : Proper (N.eq ==> N.eq ==> N.eq) def_add.
Proof.
-intros x x' Exx' y y' Eyy'. unfold def_add.
-(* TODO: why rewrite Exx' don't work here (or verrrry slowly) ? *)
-apply recursion_wd with (Aeq := N.eq); auto with *.
-apply def_add_prewd.
+unfold def_add. f_equiv'.
Qed.
Theorem def_add_0_l : forall y, 0 +++ y == y.
@@ -45,7 +64,7 @@ Qed.
Theorem def_add_succ_l : forall x y, S x +++ y == S (x +++ y).
Proof.
intros x y; unfold def_add.
-rewrite recursion_succ; auto with *.
+rewrite recursion_succ; f_equiv'.
Qed.
Theorem def_add_add : forall n m, n +++ m == n + m.
@@ -62,18 +81,10 @@ Definition def_mul (x y : N.t) := recursion 0 (fun _ p => p +++ x) y.
Local Infix "**" := def_mul (at level 40, left associativity).
-Instance def_mul_prewd :
- Proper (N.eq==>N.eq==>N.eq==>N.eq) (fun x _ p => p +++ x).
-Proof.
-repeat red; intros; now apply def_add_wd.
-Qed.
-
Instance def_mul_wd : Proper (N.eq ==> N.eq ==> N.eq) def_mul.
Proof.
-unfold def_mul.
-intros x x' Exx' y y' Eyy'.
-apply recursion_wd; auto with *.
-now apply def_mul_prewd.
+unfold def_mul. (* TODO : solve_proper SLOW + BUG *)
+f_equiv'.
Qed.
Theorem def_mul_0_r : forall x, x ** 0 == 0.
@@ -85,7 +96,7 @@ Theorem def_mul_succ_r : forall x y, x ** S y == x ** y +++ x.
Proof.
intros x y; unfold def_mul.
rewrite recursion_succ; auto with *.
-now apply def_mul_prewd.
+f_equiv'.
Qed.
Theorem def_mul_mul : forall n m, n ** m == n * m.
@@ -106,25 +117,9 @@ recursion
Local Infix "<<" := ltb (at level 70, no associativity).
-Instance ltb_prewd1 : Proper (N.eq==>Logic.eq) (if_zero false true).
-Proof.
-red; intros; apply if_zero_wd; auto.
-Qed.
-
-Instance ltb_prewd2 : Proper (N.eq==>(N.eq==>Logic.eq)==>N.eq==>Logic.eq)
- (fun _ f n => recursion false (fun n' _ => f n') n).
-Proof.
-repeat red; intros; simpl.
-apply recursion_wd; auto with *.
-repeat red; auto.
-Qed.
-
Instance ltb_wd : Proper (N.eq ==> N.eq ==> Logic.eq) ltb.
Proof.
-unfold ltb.
-intros n n' Hn m m' Hm.
-apply f_equiv; auto with *.
-apply recursion_wd; auto; [ apply ltb_prewd1 | apply ltb_prewd2 ].
+unfold ltb. f_equiv'.
Qed.
Theorem ltb_base : forall n, 0 << n = if_zero false true n.
@@ -136,11 +131,9 @@ Theorem ltb_step :
forall m n, S m << n = recursion false (fun n' _ => m << n') n.
Proof.
intros m n; unfold ltb at 1.
-apply f_equiv; auto with *.
-rewrite recursion_succ by (apply ltb_prewd1||apply ltb_prewd2).
-fold (ltb m).
-repeat red; intros. apply recursion_wd; auto.
-repeat red; intros; now apply ltb_wd.
+f_equiv.
+rewrite recursion_succ; f_equiv'.
+reflexivity.
Qed.
(* Above, we rewrite applications of function. Is it possible to rewrite
@@ -162,8 +155,7 @@ Qed.
Theorem succ_ltb_mono : forall n m, (S n << S m) = (n << m).
Proof.
intros n m.
-rewrite ltb_step. rewrite recursion_succ; try reflexivity.
-repeat red; intros; now apply ltb_wd.
+rewrite ltb_step. rewrite recursion_succ; f_equiv'.
Qed.
Theorem ltb_lt : forall n m, n << m = true <-> n < m.
@@ -188,9 +180,7 @@ Definition even (x : N.t) := recursion true (fun _ p => negb p) x.
Instance even_wd : Proper (N.eq==>Logic.eq) even.
Proof.
-intros n n' Hn. unfold even.
-apply recursion_wd; auto.
-congruence.
+unfold even. f_equiv'.
Qed.
Theorem even_0 : even 0 = true.
@@ -202,19 +192,12 @@ Qed.
Theorem even_succ : forall x, even (S x) = negb (even x).
Proof.
unfold even.
-intro x; rewrite recursion_succ; try reflexivity.
-congruence.
+intro x; rewrite recursion_succ; f_equiv'.
Qed.
(*****************************************************)
(** Division by 2 *)
-Local Notation "a <= b <= c" := (a<=b /\ b<=c).
-Local Notation "a <= b < c" := (a<=b /\ b<c).
-Local Notation "a < b <= c" := (a<b /\ b<=c).
-Local Notation "a < b < c" := (a<b /\ b<c).
-Local Notation "2" := (S 1).
-
Definition half_aux (x : N.t) : N.t * N.t :=
recursion (0, 0) (fun _ p => let (x1, x2) := p in (S x2, x1)) x.
@@ -223,14 +206,14 @@ Definition half (x : N.t) := snd (half_aux x).
Instance half_aux_wd : Proper (N.eq ==> N.eq*N.eq) half_aux.
Proof.
intros x x' Hx. unfold half_aux.
-apply recursion_wd; auto with *.
+f_equiv; trivial.
intros y y' Hy (u,v) (u',v') (Hu,Hv). compute in *.
rewrite Hu, Hv; auto with *.
Qed.
Instance half_wd : Proper (N.eq==>N.eq) half.
Proof.
-intros x x' Hx. unfold half. rewrite Hx; auto with *.
+unfold half. f_equiv'.
Qed.
Lemma half_aux_0 : half_aux 0 = (0,0).
@@ -245,8 +228,7 @@ intros.
remember (half_aux x) as h.
destruct h as (f,s); simpl in *.
unfold half_aux in *.
-rewrite recursion_succ, <- Heqh; simpl; auto.
-repeat red; intros; subst; auto.
+rewrite recursion_succ, <- Heqh; simpl; f_equiv'.
Qed.
Theorem half_aux_spec : forall n,
@@ -258,7 +240,7 @@ rewrite half_aux_0; simpl; rewrite add_0_l; auto with *.
intros.
rewrite half_aux_succ. simpl.
rewrite add_succ_l, add_comm; auto.
-apply succ_wd; auto.
+now f_equiv.
Qed.
Theorem half_aux_spec2 : forall n,
@@ -271,7 +253,7 @@ rewrite half_aux_0; simpl. auto with *.
intros.
rewrite half_aux_succ; simpl.
destruct H; auto with *.
-right; apply succ_wd; auto with *.
+right; now f_equiv.
Qed.
Theorem half_0 : half 0 == 0.
@@ -281,14 +263,14 @@ Qed.
Theorem half_1 : half 1 == 0.
Proof.
-unfold half. rewrite half_aux_succ, half_aux_0; simpl; auto with *.
+unfold half. rewrite one_succ, half_aux_succ, half_aux_0; simpl; auto with *.
Qed.
Theorem half_double : forall n,
n == 2 * half n \/ n == 1 + 2 * half n.
Proof.
intros. unfold half.
-nzsimpl.
+nzsimpl'.
destruct (half_aux_spec2 n) as [H|H]; [left|right].
rewrite <- H at 1. apply half_aux_spec.
rewrite <- add_succ_l. rewrite <- H at 1. apply half_aux_spec.
@@ -319,24 +301,23 @@ assert (LE : 0 <= half n) by apply le_0_l.
le_elim LE; auto.
destruct (half_double n) as [E|E];
rewrite <- LE, mul_0_r, ?add_0_r in E; rewrite E in LT.
-destruct (nlt_0_r _ LT).
-rewrite <- succ_lt_mono in LT.
-destruct (nlt_0_r _ LT).
+order'.
+order.
Qed.
Theorem half_decrease : forall n, 0 < n -> half n < n.
Proof.
intros n LT.
-destruct (half_double n) as [E|E]; rewrite E at 2;
- rewrite ?mul_succ_l, ?mul_0_l, ?add_0_l, ?add_assoc.
+destruct (half_double n) as [E|E]; rewrite E at 2; nzsimpl'.
rewrite <- add_0_l at 1.
rewrite <- add_lt_mono_r.
assert (LE : 0 <= half n) by apply le_0_l.
le_elim LE; auto.
rewrite <- LE, mul_0_r in E. rewrite E in LT. destruct (nlt_0_r _ LT).
+rewrite <- add_succ_l.
rewrite <- add_0_l at 1.
rewrite <- add_lt_mono_r.
-rewrite add_succ_l. apply lt_0_succ.
+apply lt_0_succ.
Qed.
@@ -347,17 +328,9 @@ Definition pow (n m : N.t) := recursion 1 (fun _ r => n*r) m.
Local Infix "^^" := pow (at level 30, right associativity).
-Instance pow_prewd :
- Proper (N.eq==>N.eq==>N.eq==>N.eq) (fun n _ r => n*r).
-Proof.
-intros n n' Hn x x' Hx y y' Hy. rewrite Hn, Hy; auto with *.
-Qed.
-
Instance pow_wd : Proper (N.eq==>N.eq==>N.eq) pow.
Proof.
-intros n n' Hn m m' Hm. unfold pow.
-apply recursion_wd; auto with *.
-now apply pow_prewd.
+unfold pow. f_equiv'.
Qed.
Lemma pow_0 : forall n, n^^0 == 1.
@@ -367,8 +340,7 @@ Qed.
Lemma pow_succ : forall n m, n^^(S m) == n*(n^^m).
Proof.
-intros. unfold pow. rewrite recursion_succ; auto with *.
-now apply pow_prewd.
+intros. unfold pow. rewrite recursion_succ; f_equiv'.
Qed.
@@ -389,15 +361,13 @@ Proof.
intros g g' Hg n n' Hn.
rewrite Hn.
destruct (n' << 2); auto with *.
-apply succ_wd.
-apply Hg. rewrite Hn; auto with *.
+f_equiv. apply Hg. now f_equiv.
Qed.
Instance log_wd : Proper (N.eq==>N.eq) log.
Proof.
intros x x' Exx'. unfold log.
-apply strong_rec_wd; auto with *.
-apply log_prewd.
+apply strong_rec_wd; f_equiv'.
Qed.
Lemma log_good_step : forall n h1 h2,
@@ -408,9 +378,9 @@ Proof.
intros n h1 h2 E.
destruct (n<<2) as [ ]_eqn:H.
auto with *.
-apply succ_wd, E, half_decrease.
-rewrite <- not_true_iff_false, ltb_lt, nlt_ge, le_succ_l in H.
-apply lt_succ_l; auto.
+f_equiv. apply E, half_decrease.
+rewrite two_succ, <- not_true_iff_false, ltb_lt, nlt_ge, le_succ_l in H.
+order'.
Qed.
Hint Resolve log_good_step.
@@ -441,14 +411,14 @@ intros n IH k Hk1 Hk2.
destruct (lt_ge_cases k 2) as [LT|LE].
(* base *)
rewrite log_init, pow_0 by auto.
-rewrite <- le_succ_l in Hk2.
+rewrite <- le_succ_l, <- one_succ in Hk2.
le_elim Hk2.
-rewrite <- nle_gt, le_succ_l in LT. destruct LT; auto.
+rewrite two_succ, <- nle_gt, le_succ_l in LT. destruct LT; auto.
rewrite <- Hk2.
rewrite half_1; auto using lt_0_1, le_refl.
(* step *)
rewrite log_step, pow_succ by auto.
-rewrite le_succ_l in LE.
+rewrite two_succ, le_succ_l in LE.
destruct (IH (half k)) as (IH1,IH2).
rewrite <- lt_succ_r. apply lt_le_trans with k; auto.
now apply half_decrease.
@@ -458,22 +428,13 @@ split.
rewrite <- le_succ_l in IH1.
apply mul_le_mono_l with (p:=2) in IH1.
eapply lt_le_trans; eauto.
-nzsimpl.
+nzsimpl'.
rewrite lt_succ_r.
eapply le_trans; [ eapply half_lower_bound | ].
-nzsimpl; apply le_refl.
+nzsimpl'; apply le_refl.
eapply le_trans; [ | eapply half_upper_bound ].
apply mul_le_mono_l; auto.
Qed.
-(** Later:
-
-Theorem log_mul : forall n m, 0 < n -> 0 < m ->
- log (n*m) == log n + log m.
-
-Theorem log_pow2 : forall n, log (2^^n) = n.
-
-*)
-
-End NdefOpsPropFunct.
+End NdefOpsProp.
diff --git a/theories/Numbers/Natural/Abstract/NDiv.v b/theories/Numbers/Natural/Abstract/NDiv.v
index 171530f0..6db8e448 100644
--- a/theories/Numbers/Natural/Abstract/NDiv.v
+++ b/theories/Numbers/Natural/Abstract/NDiv.v
@@ -1,40 +1,36 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(** Euclidean Division *)
+Require Import NAxioms NSub NZDiv.
-Require Import NAxioms NProperties NZDiv.
+(** Properties of Euclidean Division *)
-Module Type NDivSpecific (Import N : NAxiomsSig')(Import DM : DivMod' N).
- Axiom mod_upper_bound : forall a b, b ~= 0 -> a mod b < b.
-End NDivSpecific.
+Module Type NDivProp (Import N : NAxiomsSig')(Import NP : NSubProp N).
-Module Type NDivSig := NAxiomsSig <+ DivMod <+ NZDivCommon <+ NDivSpecific.
-Module Type NDivSig' := NAxiomsSig' <+ DivMod' <+ NZDivCommon <+ NDivSpecific.
+(** We benefit from what already exists for NZ *)
+Module Import Private_NZDiv := Nop <+ NZDivProp N N NP.
-Module NDivPropFunct (Import N : NDivSig')(Import NP : NPropSig N).
+Ltac auto' := try rewrite <- neq_0_lt_0; auto using le_0_l.
-(** We benefit from what already exists for NZ *)
+(** Let's now state again theorems, but without useless hypothesis. *)
- Module ND <: NZDiv N.
- Definition div := div.
- Definition modulo := modulo.
- Definition div_wd := div_wd.
- Definition mod_wd := mod_wd.
- Definition div_mod := div_mod.
- Lemma mod_bound : forall a b, 0<=a -> 0<b -> 0 <= a mod b < b.
- Proof. split. apply le_0_l. apply mod_upper_bound. order. Qed.
- End ND.
- Module Import NZDivP := NZDivPropFunct N NP ND.
+Lemma mod_upper_bound : forall a b, b ~= 0 -> a mod b < b.
+Proof. intros. apply mod_bound_pos; auto'. Qed.
- Ltac auto' := try rewrite <- neq_0_lt_0; auto using le_0_l.
+(** Another formulation of the main equation *)
-(** Let's now state again theorems, but without useless hypothesis. *)
+Lemma mod_eq :
+ forall a b, b~=0 -> a mod b == a - b*(a/b).
+Proof.
+intros.
+symmetry. apply add_sub_eq_l. symmetry.
+now apply div_mod.
+Qed.
(** Uniqueness theorems *)
@@ -51,6 +47,9 @@ Theorem mod_unique:
forall a b q r, r<b -> a == b*q + r -> r == a mod b.
Proof. intros. apply mod_unique with q; auto'. Qed.
+Theorem div_unique_exact: forall a b q, b~=0 -> a == b*q -> q == a/b.
+Proof. intros. apply div_unique_exact; auto'. Qed.
+
(** A division by itself returns 1 *)
Lemma div_same : forall a, a~=0 -> a/a == 1.
@@ -223,6 +222,10 @@ Lemma div_div : forall a b c, b~=0 -> c~=0 ->
(a/b)/c == a/(b*c).
Proof. intros. apply div_div; auto'. Qed.
+Lemma mod_mul_r : forall a b c, b~=0 -> c~=0 ->
+ a mod (b*c) == a mod b + b*((a/b) mod c).
+Proof. intros. apply mod_mul_r; auto'. Qed.
+
(** A last inequality: *)
Theorem div_mul_le:
@@ -235,5 +238,4 @@ Lemma mod_divides : forall a b, b~=0 ->
(a mod b == 0 <-> exists c, a == b*c).
Proof. intros. apply mod_divides; auto'. Qed.
-End NDivPropFunct.
-
+End NDivProp.
diff --git a/theories/Numbers/Natural/Abstract/NGcd.v b/theories/Numbers/Natural/Abstract/NGcd.v
new file mode 100644
index 00000000..ece369d8
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NGcd.v
@@ -0,0 +1,213 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Properties of the greatest common divisor *)
+
+Require Import NAxioms NSub NZGcd.
+
+Module Type NGcdProp
+ (Import A : NAxiomsSig')
+ (Import B : NSubProp A).
+
+ Include NZGcdProp A A B.
+
+(** Results concerning divisibility*)
+
+Definition divide_1_r n : (n | 1) -> n == 1
+ := divide_1_r_nonneg n (le_0_l n).
+
+Definition divide_antisym n m : (n | m) -> (m | n) -> n == m
+ := divide_antisym_nonneg n m (le_0_l n) (le_0_l m).
+
+Lemma divide_add_cancel_r : forall n m p, (n | m) -> (n | m + p) -> (n | p).
+Proof.
+ intros n m p (q,Hq) (r,Hr).
+ exists (r-q). rewrite mul_sub_distr_r, <- Hq, <- Hr.
+ now rewrite add_comm, add_sub.
+Qed.
+
+Lemma divide_sub_r : forall n m p, (n | m) -> (n | p) -> (n | m - p).
+Proof.
+ intros n m p H H'.
+ destruct (le_ge_cases m p) as [LE|LE].
+ apply sub_0_le in LE. rewrite LE. apply divide_0_r.
+ apply divide_add_cancel_r with p; trivial.
+ now rewrite add_comm, sub_add.
+Qed.
+
+(** Properties of gcd *)
+
+Definition gcd_0_l n : gcd 0 n == n := gcd_0_l_nonneg n (le_0_l n).
+Definition gcd_0_r n : gcd n 0 == n := gcd_0_r_nonneg n (le_0_l n).
+Definition gcd_diag n : gcd n n == n := gcd_diag_nonneg n (le_0_l n).
+Definition gcd_unique' n m p := gcd_unique n m p (le_0_l p).
+Definition gcd_unique_alt' n m p := gcd_unique_alt n m p (le_0_l p).
+Definition divide_gcd_iff' n m := divide_gcd_iff n m (le_0_l n).
+
+Lemma gcd_add_mult_diag_r : forall n m p, gcd n (m+p*n) == gcd n m.
+Proof.
+ intros. apply gcd_unique_alt'.
+ intros. rewrite gcd_divide_iff. split; intros (U,V); split; trivial.
+ apply divide_add_r; trivial. now apply divide_mul_r.
+ apply divide_add_cancel_r with (p*n); trivial.
+ now apply divide_mul_r. now rewrite add_comm.
+Qed.
+
+Lemma gcd_add_diag_r : forall n m, gcd n (m+n) == gcd n m.
+Proof.
+ intros n m. rewrite <- (mul_1_l n) at 2. apply gcd_add_mult_diag_r.
+Qed.
+
+Lemma gcd_sub_diag_r : forall n m, n<=m -> gcd n (m-n) == gcd n m.
+Proof.
+ intros n m H. symmetry.
+ rewrite <- (sub_add n m H) at 1. apply gcd_add_diag_r.
+Qed.
+
+(** On natural numbers, we should use a particular form
+ for the Bezout identity, since we don't have full subtraction. *)
+
+Definition Bezout n m p := exists a b, a*n == p + b*m.
+
+Instance Bezout_wd : Proper (eq==>eq==>eq==>iff) Bezout.
+Proof.
+ unfold Bezout. intros x x' Hx y y' Hy z z' Hz.
+ setoid_rewrite Hx. setoid_rewrite Hy. now setoid_rewrite Hz.
+Qed.
+
+Lemma bezout_1_gcd : forall n m, Bezout n m 1 -> gcd n m == 1.
+Proof.
+ intros n m (q & r & H).
+ apply gcd_unique; trivial using divide_1_l, le_0_1.
+ intros p Hn Hm.
+ apply divide_add_cancel_r with (r*m).
+ now apply divide_mul_r.
+ rewrite add_comm, <- H. now apply divide_mul_r.
+Qed.
+
+(** For strictly positive numbers, we have Bezout in the two directions. *)
+
+Lemma gcd_bezout_pos_pos : forall n, 0<n -> forall m, 0<m ->
+ Bezout n m (gcd n m) /\ Bezout m n (gcd n m).
+Proof.
+ intros n Hn. rewrite <- le_succ_l, <- one_succ in Hn.
+ pattern n. apply strong_right_induction with (z:=1); trivial.
+ unfold Bezout. solve_proper.
+ clear n Hn. intros n Hn IHn.
+ intros m Hm. rewrite <- le_succ_l, <- one_succ in Hm.
+ pattern m. apply strong_right_induction with (z:=1); trivial.
+ unfold Bezout. solve_proper.
+ clear m Hm. intros m Hm IHm.
+ destruct (lt_trichotomy n m) as [LT|[EQ|LT]].
+ (* n < m *)
+ destruct (IHm (m-n)) as ((a & b & EQ), (a' & b' & EQ')).
+ rewrite one_succ, le_succ_l.
+ apply lt_add_lt_sub_l; now nzsimpl.
+ apply sub_lt; order'.
+ split.
+ exists (a+b). exists b.
+ rewrite mul_add_distr_r, EQ, mul_sub_distr_l, <- add_assoc.
+ rewrite gcd_sub_diag_r by order.
+ rewrite sub_add. reflexivity. apply mul_le_mono_l; order.
+ exists a'. exists (a'+b').
+ rewrite gcd_sub_diag_r in EQ' by order.
+ rewrite (add_comm a'), mul_add_distr_r, add_assoc, <- EQ'.
+ rewrite mul_sub_distr_l, sub_add. reflexivity. apply mul_le_mono_l; order.
+ (* n = m *)
+ rewrite EQ. rewrite gcd_diag.
+ split.
+ exists 1. exists 0. now nzsimpl.
+ exists 1. exists 0. now nzsimpl.
+ (* m < n *)
+ rewrite gcd_comm, and_comm.
+ apply IHn; trivial.
+ now rewrite <- le_succ_l, <- one_succ.
+Qed.
+
+Lemma gcd_bezout_pos : forall n m, 0<n -> Bezout n m (gcd n m).
+Proof.
+ intros n m Hn.
+ destruct (eq_0_gt_0_cases m) as [EQ|LT].
+ rewrite EQ, gcd_0_r. exists 1. exists 0. now nzsimpl.
+ now apply gcd_bezout_pos_pos.
+Qed.
+
+(** For arbitrary natural numbers, we could only say that at least
+ one of the Bezout identities holds. *)
+
+Lemma gcd_bezout : forall n m,
+ Bezout n m (gcd n m) \/ Bezout m n (gcd n m).
+Proof.
+ intros n m.
+ destruct (eq_0_gt_0_cases n) as [EQ|LT].
+ right. rewrite EQ, gcd_0_l. exists 1. exists 0. now nzsimpl.
+ left. now apply gcd_bezout_pos.
+Qed.
+
+Lemma gcd_mul_mono_l :
+ forall n m p, gcd (p * n) (p * m) == p * gcd n m.
+Proof.
+ intros n m p.
+ apply gcd_unique'.
+ apply mul_divide_mono_l, gcd_divide_l.
+ apply mul_divide_mono_l, gcd_divide_r.
+ intros q H H'.
+ destruct (eq_0_gt_0_cases n) as [EQ|LT].
+ rewrite EQ in *. now rewrite gcd_0_l.
+ destruct (gcd_bezout_pos n m) as (a & b & EQ); trivial.
+ apply divide_add_cancel_r with (p*m*b).
+ now apply divide_mul_l.
+ rewrite <- mul_assoc, <- mul_add_distr_l, add_comm, (mul_comm m), <- EQ.
+ rewrite (mul_comm a), mul_assoc.
+ now apply divide_mul_l.
+Qed.
+
+Lemma gcd_mul_mono_r :
+ forall n m p, gcd (n*p) (m*p) == gcd n m * p.
+Proof.
+ intros. rewrite !(mul_comm _ p). apply gcd_mul_mono_l.
+Qed.
+
+Lemma gauss : forall n m p, (n | m * p) -> gcd n m == 1 -> (n | p).
+Proof.
+ intros n m p H G.
+ destruct (eq_0_gt_0_cases n) as [EQ|LT].
+ rewrite EQ in *. rewrite gcd_0_l in G. now rewrite <- (mul_1_l p), <- G.
+ destruct (gcd_bezout_pos n m) as (a & b & EQ); trivial.
+ rewrite G in EQ.
+ apply divide_add_cancel_r with (m*p*b).
+ now apply divide_mul_l.
+ rewrite (mul_comm _ b), mul_assoc. rewrite <- (mul_1_l p) at 2.
+ rewrite <- mul_add_distr_r, add_comm, <- EQ.
+ now apply divide_mul_l, divide_factor_r.
+Qed.
+
+Lemma divide_mul_split : forall n m p, n ~= 0 -> (n | m * p) ->
+ exists q r, n == q*r /\ (q | m) /\ (r | p).
+Proof.
+ intros n m p Hn H.
+ assert (G := gcd_nonneg n m). le_elim G.
+ destruct (gcd_divide_l n m) as (q,Hq).
+ exists (gcd n m). exists q.
+ split. now rewrite mul_comm.
+ split. apply gcd_divide_r.
+ destruct (gcd_divide_r n m) as (r,Hr).
+ rewrite Hr in H. rewrite Hq in H at 1.
+ rewrite mul_shuffle0 in H. apply mul_divide_cancel_r in H; [|order].
+ apply gauss with r; trivial.
+ apply mul_cancel_r with (gcd n m); [order|].
+ rewrite mul_1_l.
+ rewrite <- gcd_mul_mono_r, <- Hq, <- Hr; order.
+ symmetry in G. apply gcd_eq_0 in G. destruct G as (Hn',_); order.
+Qed.
+
+(** TODO : relation between gcd and division and modulo *)
+
+(** TODO : more about rel_prime (i.e. gcd == 1), about prime ... *)
+
+End NGcdProp.
diff --git a/theories/Numbers/Natural/Abstract/NIso.v b/theories/Numbers/Natural/Abstract/NIso.v
index d484a625..bcf746a7 100644
--- a/theories/Numbers/Natural/Abstract/NIso.v
+++ b/theories/Numbers/Natural/Abstract/NIso.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,11 +8,9 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NIso.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import NBase.
-Module Homomorphism (N1 N2 : NAxiomsSig).
+Module Homomorphism (N1 N2 : NAxiomsRecSig).
Local Notation "n == m" := (N2.eq n m) (at level 70, no associativity).
@@ -25,11 +23,8 @@ Definition natural_isomorphism : N1.t -> N2.t :=
Instance natural_isomorphism_wd : Proper (N1.eq ==> N2.eq) natural_isomorphism.
Proof.
unfold natural_isomorphism.
-intros n m Eqxy.
-apply N1.recursion_wd.
-reflexivity.
-intros _ _ _ y' y'' H. now apply N2.succ_wd.
-assumption.
+repeat red; intros. f_equiv; trivial.
+repeat red; intros. now f_equiv.
Qed.
Theorem natural_isomorphism_0 : natural_isomorphism N1.zero == N2.zero.
@@ -42,7 +37,7 @@ Theorem natural_isomorphism_succ :
Proof.
unfold natural_isomorphism.
intro n. rewrite N1.recursion_succ; auto with *.
-repeat red; intros. apply N2.succ_wd; auto.
+repeat red; intros. now f_equiv.
Qed.
Theorem hom_nat_iso : homomorphism natural_isomorphism.
@@ -53,9 +48,9 @@ Qed.
End Homomorphism.
-Module Inverse (N1 N2 : NAxiomsSig).
+Module Inverse (N1 N2 : NAxiomsRecSig).
-Module Import NBasePropMod1 := NBasePropFunct N1.
+Module Import NBasePropMod1 := NBaseProp N1.
(* This makes the tactic induct available. Since it is taken from
(NBasePropFunct NAxiomsMod1), it refers to induction on N1. *)
@@ -76,7 +71,7 @@ Qed.
End Inverse.
-Module Isomorphism (N1 N2 : NAxiomsSig).
+Module Isomorphism (N1 N2 : NAxiomsRecSig).
Module Hom12 := Homomorphism N1 N2.
Module Hom21 := Homomorphism N2 N1.
diff --git a/theories/Numbers/Natural/Abstract/NLcm.v b/theories/Numbers/Natural/Abstract/NLcm.v
new file mode 100644
index 00000000..1e8e678c
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NLcm.v
@@ -0,0 +1,290 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import NAxioms NSub NDiv NGcd.
+
+(** * Least Common Multiple *)
+
+(** Unlike other functions around, we will define lcm below instead of
+ axiomatizing it. Indeed, there is no "prior art" about lcm in the
+ standard library to be compliant with, and the generic definition
+ of lcm via gcd is quite reasonable.
+
+ By the way, we also state here some combined properties of div/mod
+ and gcd.
+*)
+
+Module Type NLcmProp
+ (Import A : NAxiomsSig')
+ (Import B : NSubProp A)
+ (Import C : NDivProp A B)
+ (Import D : NGcdProp A B).
+
+(** Divibility and modulo *)
+
+Lemma mod_divide : forall a b, b~=0 -> (a mod b == 0 <-> (b|a)).
+Proof.
+ intros a b Hb. split.
+ intros Hab. exists (a/b). rewrite mul_comm.
+ rewrite (div_mod a b Hb) at 1. rewrite Hab; now nzsimpl.
+ intros (c,Hc). rewrite Hc. now apply mod_mul.
+Qed.
+
+Lemma divide_div_mul_exact : forall a b c, b~=0 -> (b|a) ->
+ (c*a)/b == c*(a/b).
+Proof.
+ intros a b c Hb H.
+ apply mul_cancel_l with b; trivial.
+ rewrite mul_assoc, mul_shuffle0.
+ assert (H':=H). apply mod_divide, div_exact in H'; trivial.
+ rewrite <- H', (mul_comm a c).
+ symmetry. apply div_exact; trivial.
+ apply mod_divide; trivial.
+ now apply divide_mul_r.
+Qed.
+
+(** Gcd of divided elements, for exact divisions *)
+
+Lemma gcd_div_factor : forall a b c, c~=0 -> (c|a) -> (c|b) ->
+ gcd (a/c) (b/c) == (gcd a b)/c.
+Proof.
+ intros a b c Hc Ha Hb.
+ apply mul_cancel_l with c; try order.
+ assert (H:=gcd_greatest _ _ _ Ha Hb).
+ apply mod_divide, div_exact in H; try order.
+ rewrite <- H.
+ rewrite <- gcd_mul_mono_l; try order.
+ f_equiv; symmetry; apply div_exact; try order;
+ apply mod_divide; trivial; try order.
+Qed.
+
+Lemma gcd_div_gcd : forall a b g, g~=0 -> g == gcd a b ->
+ gcd (a/g) (b/g) == 1.
+Proof.
+ intros a b g NZ EQ. rewrite gcd_div_factor.
+ now rewrite <- EQ, div_same.
+ generalize (gcd_nonneg a b); order.
+ rewrite EQ; apply gcd_divide_l.
+ rewrite EQ; apply gcd_divide_r.
+Qed.
+
+(** The following equality is crucial for Euclid algorithm *)
+
+Lemma gcd_mod : forall a b, b~=0 -> gcd (a mod b) b == gcd b a.
+Proof.
+ intros a b Hb. rewrite (gcd_comm _ b).
+ rewrite <- (gcd_add_mult_diag_r b (a mod b) (a/b)).
+ now rewrite add_comm, mul_comm, <- div_mod.
+Qed.
+
+(** We now define lcm thanks to gcd:
+
+ lcm a b = a * (b / gcd a b)
+ = (a / gcd a b) * b
+ = (a*b) / gcd a b
+
+ Nota: [lcm 0 0] should be 0, which isn't garantee with the third
+ equation above.
+*)
+
+Definition lcm a b := a*(b/gcd a b).
+
+Instance lcm_wd : Proper (eq==>eq==>eq) lcm.
+Proof. unfold lcm. solve_proper. Qed.
+
+Lemma lcm_equiv1 : forall a b, gcd a b ~= 0 ->
+ a * (b / gcd a b) == (a*b)/gcd a b.
+Proof.
+ intros a b H. rewrite divide_div_mul_exact; try easy. apply gcd_divide_r.
+Qed.
+
+Lemma lcm_equiv2 : forall a b, gcd a b ~= 0 ->
+ (a / gcd a b) * b == (a*b)/gcd a b.
+Proof.
+ intros a b H. rewrite 2 (mul_comm _ b).
+ rewrite divide_div_mul_exact; try easy. apply gcd_divide_l.
+Qed.
+
+Lemma gcd_div_swap : forall a b,
+ (a / gcd a b) * b == a * (b / gcd a b).
+Proof.
+ intros a b. destruct (eq_decidable (gcd a b) 0) as [EQ|NEQ].
+ apply gcd_eq_0 in EQ. destruct EQ as (EQ,EQ'). rewrite EQ, EQ'. now nzsimpl.
+ now rewrite lcm_equiv1, <-lcm_equiv2.
+Qed.
+
+Lemma divide_lcm_l : forall a b, (a | lcm a b).
+Proof.
+ unfold lcm. intros a b. apply divide_factor_l.
+Qed.
+
+Lemma divide_lcm_r : forall a b, (b | lcm a b).
+Proof.
+ unfold lcm. intros a b. rewrite <- gcd_div_swap.
+ apply divide_factor_r.
+Qed.
+
+Lemma divide_div : forall a b c, a~=0 -> (a|b) -> (b|c) -> (b/a|c/a).
+Proof.
+ intros a b c Ha Hb (c',Hc). exists c'.
+ now rewrite <- divide_div_mul_exact, Hc.
+Qed.
+
+Lemma lcm_least : forall a b c,
+ (a | c) -> (b | c) -> (lcm a b | c).
+Proof.
+ intros a b c Ha Hb. unfold lcm.
+ destruct (eq_decidable (gcd a b) 0) as [EQ|NEQ].
+ apply gcd_eq_0 in EQ. destruct EQ as (EQ,EQ'). rewrite EQ in *. now nzsimpl.
+ assert (Ga := gcd_divide_l a b).
+ assert (Gb := gcd_divide_r a b).
+ set (g:=gcd a b) in *.
+ assert (Ha' := divide_div g a c NEQ Ga Ha).
+ assert (Hb' := divide_div g b c NEQ Gb Hb).
+ destruct Ha' as (a',Ha'). rewrite Ha', mul_comm in Hb'.
+ apply gauss in Hb'; [|apply gcd_div_gcd; unfold g; trivial using gcd_comm].
+ destruct Hb' as (b',Hb').
+ exists b'.
+ rewrite mul_shuffle3, <- Hb'.
+ rewrite (proj2 (div_exact c g NEQ)).
+ rewrite Ha', mul_shuffle3, (mul_comm a a'). f_equiv.
+ symmetry. apply div_exact; trivial.
+ apply mod_divide; trivial.
+ apply mod_divide; trivial. transitivity a; trivial.
+Qed.
+
+Lemma lcm_comm : forall a b, lcm a b == lcm b a.
+Proof.
+ intros a b. unfold lcm. rewrite (gcd_comm b), (mul_comm b).
+ now rewrite <- gcd_div_swap.
+Qed.
+
+Lemma lcm_divide_iff : forall n m p,
+ (lcm n m | p) <-> (n | p) /\ (m | p).
+Proof.
+ intros. split. split.
+ transitivity (lcm n m); trivial using divide_lcm_l.
+ transitivity (lcm n m); trivial using divide_lcm_r.
+ intros (H,H'). now apply lcm_least.
+Qed.
+
+Lemma lcm_unique : forall n m p,
+ 0<=p -> (n|p) -> (m|p) ->
+ (forall q, (n|q) -> (m|q) -> (p|q)) ->
+ lcm n m == p.
+Proof.
+ intros n m p Hp Hn Hm H.
+ apply divide_antisym; trivial.
+ now apply lcm_least.
+ apply H. apply divide_lcm_l. apply divide_lcm_r.
+Qed.
+
+Lemma lcm_unique_alt : forall n m p, 0<=p ->
+ (forall q, (p|q) <-> (n|q) /\ (m|q)) ->
+ lcm n m == p.
+Proof.
+ intros n m p Hp H.
+ apply lcm_unique; trivial.
+ apply H, divide_refl.
+ apply H, divide_refl.
+ intros. apply H. now split.
+Qed.
+
+Lemma lcm_assoc : forall n m p, lcm n (lcm m p) == lcm (lcm n m) p.
+Proof.
+ intros. apply lcm_unique_alt. apply le_0_l.
+ intros. now rewrite !lcm_divide_iff, and_assoc.
+Qed.
+
+Lemma lcm_0_l : forall n, lcm 0 n == 0.
+Proof.
+ intros. apply lcm_unique; trivial. order.
+ apply divide_refl.
+ apply divide_0_r.
+Qed.
+
+Lemma lcm_0_r : forall n, lcm n 0 == 0.
+Proof.
+ intros. now rewrite lcm_comm, lcm_0_l.
+Qed.
+
+Lemma lcm_1_l : forall n, lcm 1 n == n.
+Proof.
+ intros. apply lcm_unique; trivial using divide_1_l, le_0_l, divide_refl.
+Qed.
+
+Lemma lcm_1_r : forall n, lcm n 1 == n.
+Proof.
+ intros. now rewrite lcm_comm, lcm_1_l.
+Qed.
+
+Lemma lcm_diag : forall n, lcm n n == n.
+Proof.
+ intros. apply lcm_unique; trivial using divide_refl, le_0_l.
+Qed.
+
+Lemma lcm_eq_0 : forall n m, lcm n m == 0 <-> n == 0 \/ m == 0.
+Proof.
+ intros. split.
+ intros EQ.
+ apply eq_mul_0.
+ apply divide_0_l. rewrite <- EQ. apply lcm_least.
+ apply divide_factor_l. apply divide_factor_r.
+ destruct 1 as [EQ|EQ]; rewrite EQ. apply lcm_0_l. apply lcm_0_r.
+Qed.
+
+Lemma divide_lcm_eq_r : forall n m, (n|m) -> lcm n m == m.
+Proof.
+ intros n m H. apply lcm_unique_alt; trivial using le_0_l.
+ intros q. split. split; trivial. now transitivity m.
+ now destruct 1.
+Qed.
+
+Lemma divide_lcm_iff : forall n m, (n|m) <-> lcm n m == m.
+Proof.
+ intros n m. split. now apply divide_lcm_eq_r.
+ intros EQ. rewrite <- EQ. apply divide_lcm_l.
+Qed.
+
+Lemma lcm_mul_mono_l :
+ forall n m p, lcm (p * n) (p * m) == p * lcm n m.
+Proof.
+ intros n m p.
+ destruct (eq_decidable p 0) as [Hp|Hp].
+ rewrite Hp. nzsimpl. rewrite lcm_0_l. now nzsimpl.
+ destruct (eq_decidable (gcd n m) 0) as [Hg|Hg].
+ apply gcd_eq_0 in Hg. destruct Hg as (Hn,Hm); rewrite Hn, Hm.
+ nzsimpl. rewrite lcm_0_l. now nzsimpl.
+ unfold lcm.
+ rewrite gcd_mul_mono_l.
+ rewrite mul_assoc. f_equiv.
+ now rewrite div_mul_cancel_l.
+Qed.
+
+Lemma lcm_mul_mono_r :
+ forall n m p, lcm (n * p) (m * p) == lcm n m * p.
+Proof.
+ intros n m p. now rewrite !(mul_comm _ p), lcm_mul_mono_l, mul_comm.
+Qed.
+
+Lemma gcd_1_lcm_mul : forall n m, n~=0 -> m~=0 ->
+ (gcd n m == 1 <-> lcm n m == n*m).
+Proof.
+ intros n m Hn Hm. split; intros H.
+ unfold lcm. rewrite H. now rewrite div_1_r.
+ unfold lcm in *.
+ apply mul_cancel_l in H; trivial.
+ assert (Hg : gcd n m ~= 0) by (red; rewrite gcd_eq_0; destruct 1; order).
+ assert (H' := gcd_divide_r n m).
+ apply mod_divide in H'; trivial. apply div_exact in H'; trivial.
+ rewrite H in H'.
+ rewrite <- (mul_1_l m) in H' at 1.
+ now apply mul_cancel_r in H'.
+Qed.
+
+End NLcmProp.
diff --git a/theories/Numbers/Natural/Abstract/NLog.v b/theories/Numbers/Natural/Abstract/NLog.v
new file mode 100644
index 00000000..74827c6e
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NLog.v
@@ -0,0 +1,23 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Base-2 Logarithm Properties *)
+
+Require Import NAxioms NSub NPow NParity NZLog.
+
+Module Type NLog2Prop
+ (A : NAxiomsSig)
+ (B : NSubProp A)
+ (C : NParityProp A B)
+ (D : NPowProp A B C).
+
+ (** For the moment we simply reuse NZ properties *)
+
+ Include NZLog2Prop A A A B D.Private_NZPow.
+ Include NZLog2UpProp A A A B D.Private_NZPow.
+End NLog2Prop.
diff --git a/theories/Numbers/Natural/Abstract/NMaxMin.v b/theories/Numbers/Natural/Abstract/NMaxMin.v
new file mode 100644
index 00000000..cdff6dbc
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NMaxMin.v
@@ -0,0 +1,135 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import NAxioms NSub GenericMinMax.
+
+(** * Properties of minimum and maximum specific to natural numbers *)
+
+Module Type NMaxMinProp (Import N : NAxiomsMiniSig').
+Include NSubProp N.
+
+(** Zero *)
+
+Lemma max_0_l : forall n, max 0 n == n.
+Proof.
+ intros. apply max_r. apply le_0_l.
+Qed.
+
+Lemma max_0_r : forall n, max n 0 == n.
+Proof.
+ intros. apply max_l. apply le_0_l.
+Qed.
+
+Lemma min_0_l : forall n, min 0 n == 0.
+Proof.
+ intros. apply min_l. apply le_0_l.
+Qed.
+
+Lemma min_0_r : forall n, min n 0 == 0.
+Proof.
+ intros. apply min_r. apply le_0_l.
+Qed.
+
+(** The following results are concrete instances of [max_monotone]
+ and similar lemmas. *)
+
+(** Succ *)
+
+Lemma succ_max_distr : forall n m, S (max n m) == max (S n) (S m).
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?succ_le_mono.
+Qed.
+
+Lemma succ_min_distr : forall n m, S (min n m) == min (S n) (S m).
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?succ_le_mono.
+Qed.
+
+(** Add *)
+
+Lemma add_max_distr_l : forall n m p, max (p + n) (p + m) == p + max n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?add_le_mono_l.
+Qed.
+
+Lemma add_max_distr_r : forall n m p, max (n + p) (m + p) == max n m + p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; now rewrite <- ?add_le_mono_r.
+Qed.
+
+Lemma add_min_distr_l : forall n m p, min (p + n) (p + m) == p + min n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?add_le_mono_l.
+Qed.
+
+Lemma add_min_distr_r : forall n m p, min (n + p) (m + p) == min n m + p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; now rewrite <- ?add_le_mono_r.
+Qed.
+
+(** Mul *)
+
+Lemma mul_max_distr_l : forall n m p, max (p * n) (p * m) == p * max n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; try order; now apply mul_le_mono_l.
+Qed.
+
+Lemma mul_max_distr_r : forall n m p, max (n * p) (m * p) == max n m * p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; try order; now apply mul_le_mono_r.
+Qed.
+
+Lemma mul_min_distr_l : forall n m p, min (p * n) (p * m) == p * min n m.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; try order; now apply mul_le_mono_l.
+Qed.
+
+Lemma mul_min_distr_r : forall n m p, min (n * p) (m * p) == min n m * p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; try order; now apply mul_le_mono_r.
+Qed.
+
+(** Sub *)
+
+Lemma sub_max_distr_l : forall n m p, max (p - n) (p - m) == p - min n m.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite min_l by trivial. apply max_l. now apply sub_le_mono_l.
+ rewrite min_r by trivial. apply max_r. now apply sub_le_mono_l.
+Qed.
+
+Lemma sub_max_distr_r : forall n m p, max (n - p) (m - p) == max n m - p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 max_r | rewrite 2 max_l]; try order; now apply sub_le_mono_r.
+Qed.
+
+Lemma sub_min_distr_l : forall n m p, min (p - n) (p - m) == p - max n m.
+Proof.
+ intros. destruct (le_ge_cases n m).
+ rewrite max_r by trivial. apply min_r. now apply sub_le_mono_l.
+ rewrite max_l by trivial. apply min_l. now apply sub_le_mono_l.
+Qed.
+
+Lemma sub_min_distr_r : forall n m p, min (n - p) (m - p) == min n m - p.
+Proof.
+ intros. destruct (le_ge_cases n m);
+ [rewrite 2 min_l | rewrite 2 min_r]; try order; now apply sub_le_mono_r.
+Qed.
+
+End NMaxMinProp.
diff --git a/theories/Numbers/Natural/Abstract/NMulOrder.v b/theories/Numbers/Natural/Abstract/NMulOrder.v
index bdd4b674..1d6e8ba0 100644
--- a/theories/Numbers/Natural/Abstract/NMulOrder.v
+++ b/theories/Numbers/Natural/Abstract/NMulOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NMulOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NAddOrder.
-Module NMulOrderPropFunct (Import N : NAxiomsSig').
-Include NAddOrderPropFunct N.
+Module NMulOrderProp (Import N : NAxiomsMiniSig').
+Include NAddOrderProp N.
(** Theorems that are either not valid on Z or have different proofs
on N and Z *)
@@ -55,7 +53,7 @@ Qed.
Theorem lt_0_mul' : forall n m, n * m > 0 <-> n > 0 /\ m > 0.
Proof.
intros n m; split; [intro H | intros [H1 H2]].
-apply -> lt_0_mul in H. destruct H as [[H1 H2] | [H1 H2]]. now split.
+apply lt_0_mul in H. destruct H as [[H1 H2] | [H1 H2]]. now split.
false_hyp H1 nlt_0_r.
now apply mul_pos_pos.
Qed.
@@ -67,14 +65,18 @@ Proof.
intros n m.
split; [| intros [H1 H2]; now rewrite H1, H2, mul_1_l].
intro H; destruct (lt_trichotomy n 1) as [H1 | [H1 | H1]].
-apply -> lt_1_r in H1. rewrite H1, mul_0_l in H. false_hyp H neq_0_succ.
+apply lt_1_r in H1. rewrite H1, mul_0_l in H. order'.
rewrite H1, mul_1_l in H; now split.
destruct (eq_0_gt_0_cases m) as [H2 | H2].
-rewrite H2, mul_0_r in H; false_hyp H neq_0_succ.
-apply -> (mul_lt_mono_pos_r m) in H1; [| assumption]. rewrite mul_1_l in H1.
+rewrite H2, mul_0_r in H. order'.
+apply (mul_lt_mono_pos_r m) in H1; [| assumption]. rewrite mul_1_l in H1.
assert (H3 : 1 < n * m) by now apply (lt_1_l m).
rewrite H in H3; false_hyp H3 lt_irrefl.
Qed.
-End NMulOrderPropFunct.
+(** Alternative name : *)
+
+Definition mul_eq_1 := eq_mul_1.
+
+End NMulOrderProp.
diff --git a/theories/Numbers/Natural/Abstract/NOrder.v b/theories/Numbers/Natural/Abstract/NOrder.v
index 17dd3466..8bba7d72 100644
--- a/theories/Numbers/Natural/Abstract/NOrder.v
+++ b/theories/Numbers/Natural/Abstract/NOrder.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,18 +8,16 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NOrder.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NAdd.
-Module NOrderPropFunct (Import N : NAxiomsSig').
-Include NAddPropFunct N.
+Module NOrderProp (Import N : NAxiomsMiniSig').
+Include NAddProp N.
(* Theorems that are true for natural numbers but not for integers *)
Theorem lt_wf_0 : well_founded lt.
Proof.
-setoid_replace lt with (fun n m => 0 <= n /\ n < m).
+setoid_replace lt with (fun n m => 0 <= n < m).
apply lt_wf.
intros x y; split.
intro H; split; [apply le_0_l | assumption]. now intros [_ H].
@@ -29,12 +27,12 @@ Defined.
Theorem nlt_0_r : forall n, ~ n < 0.
Proof.
-intro n; apply -> le_ngt. apply le_0_l.
+intro n; apply le_ngt. apply le_0_l.
Qed.
Theorem nle_succ_0 : forall n, ~ (S n <= 0).
Proof.
-intros n H; apply -> le_succ_l in H; false_hyp H nlt_0_r.
+intros n H; apply le_succ_l in H; false_hyp H nlt_0_r.
Qed.
Theorem le_0_r : forall n, n <= 0 <-> n == 0.
@@ -65,6 +63,7 @@ Qed.
Theorem zero_one : forall n, n == 0 \/ n == 1 \/ 1 < n.
Proof.
+setoid_rewrite one_succ.
induct n. now left.
cases n. intros; right; now left.
intros n IH. destruct IH as [H | [H | H]].
@@ -75,6 +74,7 @@ Qed.
Theorem lt_1_r : forall n, n < 1 <-> n == 0.
Proof.
+setoid_rewrite one_succ.
cases n.
split; intro; [reflexivity | apply lt_succ_diag_r].
intros n. rewrite <- succ_lt_mono.
@@ -83,6 +83,7 @@ Qed.
Theorem le_1_r : forall n, n <= 1 <-> n == 0 \/ n == 1.
Proof.
+setoid_rewrite one_succ.
cases n.
split; intro; [now left | apply le_succ_diag_r].
intro n. rewrite <- succ_le_mono, le_0_r, succ_inj_wd.
@@ -117,9 +118,9 @@ Proof.
intros Base Step; induct n.
intros; apply Base.
intros n IH m H. elim H using le_ind.
-solve_predicate_wd.
+solve_proper.
apply Step; [| apply IH]; now apply eq_le_incl.
-intros k H1 H2. apply -> le_succ_l in H1. apply lt_le_incl in H1. auto.
+intros k H1 H2. apply le_succ_l in H1. apply lt_le_incl in H1. auto.
Qed.
Theorem lt_ind_rel :
@@ -131,7 +132,7 @@ intros Base Step; induct n.
intros m H. apply lt_exists_pred in H; destruct H as [m' [H _]].
rewrite H; apply Base.
intros n IH m H. elim H using lt_ind.
-solve_predicate_wd.
+solve_proper.
apply Step; [| apply IH]; now apply lt_succ_diag_r.
intros k H1 H2. apply lt_succ_l in H1. auto.
Qed.
@@ -175,7 +176,7 @@ Theorem lt_le_pred : forall n m, n < m -> n <= P m.
Proof.
intro n; cases m.
intro H; false_hyp H nlt_0_r.
-intros m IH. rewrite pred_succ; now apply -> lt_succ_r.
+intros m IH. rewrite pred_succ; now apply lt_succ_r.
Qed.
Theorem lt_pred_le : forall n m, P n < m -> n <= m.
@@ -183,7 +184,7 @@ Theorem lt_pred_le : forall n m, P n < m -> n <= m.
Proof.
intros n m; cases n.
rewrite pred_0; intro H; now apply lt_le_incl.
-intros n IH. rewrite pred_succ in IH. now apply <- le_succ_l.
+intros n IH. rewrite pred_succ in IH. now apply le_succ_l.
Qed.
Theorem lt_pred_lt : forall n m, n < P m -> n < m.
@@ -200,7 +201,7 @@ Theorem pred_le_mono : forall n m, n <= m -> P n <= P m.
(* Converse is false for n == 1, m == 0 *)
Proof.
intros n m H; elim H using le_ind_rel.
-solve_relation_wd.
+solve_proper.
intro; rewrite pred_0; apply le_0_l.
intros p q H1 _; now do 2 rewrite pred_succ.
Qed.
@@ -208,12 +209,12 @@ Qed.
Theorem pred_lt_mono : forall n m, n ~= 0 -> (n < m <-> P n < P m).
Proof.
intros n m H1; split; intro H2.
-assert (m ~= 0). apply <- neq_0_lt_0. now apply lt_lt_0 with n.
+assert (m ~= 0). apply neq_0_lt_0. now apply lt_lt_0 with n.
now rewrite <- (succ_pred n) in H2; rewrite <- (succ_pred m) in H2 ;
-[apply <- succ_lt_mono | | |].
-assert (m ~= 0). apply <- neq_0_lt_0. apply lt_lt_0 with (P n).
+[apply succ_lt_mono | | |].
+assert (m ~= 0). apply neq_0_lt_0. apply lt_lt_0 with (P n).
apply lt_le_trans with (P m). assumption. apply le_pred_l.
-apply -> succ_lt_mono in H2. now do 2 rewrite succ_pred in H2.
+apply succ_lt_mono in H2. now do 2 rewrite succ_pred in H2.
Qed.
Theorem lt_succ_lt_pred : forall n m, S n < m <-> n < P m.
@@ -224,13 +225,13 @@ Qed.
Theorem le_succ_le_pred : forall n m, S n <= m -> n <= P m.
(* Converse is false for n == m == 0 *)
Proof.
-intros n m H. apply lt_le_pred. now apply -> le_succ_l.
+intros n m H. apply lt_le_pred. now apply le_succ_l.
Qed.
Theorem lt_pred_lt_succ : forall n m, P n < m -> n < S m.
(* Converse is false for n == m == 0 *)
Proof.
-intros n m H. apply <- lt_succ_r. now apply lt_pred_le.
+intros n m H. apply lt_succ_r. now apply lt_pred_le.
Qed.
Theorem le_pred_le_succ : forall n m, P n <= m <-> n <= S m.
@@ -240,5 +241,5 @@ rewrite pred_0. split; intro H; apply le_0_l.
intro n. rewrite pred_succ. apply succ_le_mono.
Qed.
-End NOrderPropFunct.
+End NOrderProp.
diff --git a/theories/Numbers/Natural/Abstract/NParity.v b/theories/Numbers/Natural/Abstract/NParity.v
new file mode 100644
index 00000000..6a1e20ce
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NParity.v
@@ -0,0 +1,63 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+Require Import Bool NSub NZParity.
+
+(** Some additionnal properties of [even], [odd]. *)
+
+Module Type NParityProp (Import N : NAxiomsSig')(Import NP : NSubProp N).
+
+Include NZParityProp N N NP.
+
+Lemma odd_pred : forall n, n~=0 -> odd (P n) = even n.
+Proof.
+ intros. rewrite <- (succ_pred n) at 2 by trivial.
+ symmetry. apply even_succ.
+Qed.
+
+Lemma even_pred : forall n, n~=0 -> even (P n) = odd n.
+Proof.
+ intros. rewrite <- (succ_pred n) at 2 by trivial.
+ symmetry. apply odd_succ.
+Qed.
+
+Lemma even_sub : forall n m, m<=n -> even (n-m) = Bool.eqb (even n) (even m).
+Proof.
+ intros.
+ case_eq (even n); case_eq (even m);
+ rewrite <- ?negb_true_iff, ?negb_even, ?odd_spec, ?even_spec;
+ intros (m',Hm) (n',Hn).
+ exists (n'-m'). now rewrite mul_sub_distr_l, Hn, Hm.
+ exists (n'-m'-1).
+ rewrite !mul_sub_distr_l, Hn, Hm, sub_add_distr, mul_1_r.
+ rewrite two_succ at 5. rewrite <- (add_1_l 1). rewrite sub_add_distr.
+ symmetry. apply sub_add.
+ apply le_add_le_sub_l.
+ rewrite add_1_l, <- two_succ, <- (mul_1_r 2) at 1.
+ rewrite <- mul_sub_distr_l. rewrite <- mul_le_mono_pos_l by order'.
+ rewrite one_succ, le_succ_l. rewrite <- lt_add_lt_sub_l, add_0_r.
+ destruct (le_gt_cases n' m') as [LE|GT]; trivial.
+ generalize (double_below _ _ LE). order.
+ exists (n'-m'). rewrite mul_sub_distr_l, Hn, Hm.
+ apply add_sub_swap.
+ apply mul_le_mono_pos_l; try order'.
+ destruct (le_gt_cases m' n') as [LE|GT]; trivial.
+ generalize (double_above _ _ GT). order.
+ exists (n'-m'). rewrite Hm,Hn, mul_sub_distr_l.
+ rewrite sub_add_distr. rewrite add_sub_swap. apply add_sub.
+ apply succ_le_mono.
+ rewrite add_1_r in Hm,Hn. order.
+Qed.
+
+Lemma odd_sub : forall n m, m<=n -> odd (n-m) = xorb (odd n) (odd m).
+Proof.
+ intros. rewrite <- !negb_even. rewrite even_sub by trivial.
+ now destruct (even n), (even m).
+Qed.
+
+End NParityProp.
diff --git a/theories/Numbers/Natural/Abstract/NPow.v b/theories/Numbers/Natural/Abstract/NPow.v
new file mode 100644
index 00000000..07aee9c6
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NPow.v
@@ -0,0 +1,160 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Properties of the power function *)
+
+Require Import Bool NAxioms NSub NParity NZPow.
+
+(** Derived properties of power, specialized on natural numbers *)
+
+Module Type NPowProp
+ (Import A : NAxiomsSig')
+ (Import B : NSubProp A)
+ (Import C : NParityProp A B).
+
+ Module Import Private_NZPow := Nop <+ NZPowProp A A B.
+
+Ltac auto' := trivial; try rewrite <- neq_0_lt_0; auto using le_0_l.
+Ltac wrap l := intros; apply l; auto'.
+
+Lemma pow_succ_r' : forall a b, a^(S b) == a * a^b.
+Proof. wrap pow_succ_r. Qed.
+
+(** Power and basic constants *)
+
+Lemma pow_0_l : forall a, a~=0 -> 0^a == 0.
+Proof. wrap pow_0_l. Qed.
+
+Definition pow_1_r : forall a, a^1 == a
+ := pow_1_r.
+
+Lemma pow_1_l : forall a, 1^a == 1.
+Proof. wrap pow_1_l. Qed.
+
+Definition pow_2_r : forall a, a^2 == a*a
+ := pow_2_r.
+
+(** Power and addition, multiplication *)
+
+Lemma pow_add_r : forall a b c, a^(b+c) == a^b * a^c.
+Proof. wrap pow_add_r. Qed.
+
+Lemma pow_mul_l : forall a b c, (a*b)^c == a^c * b^c.
+Proof. wrap pow_mul_l. Qed.
+
+Lemma pow_mul_r : forall a b c, a^(b*c) == (a^b)^c.
+Proof. wrap pow_mul_r. Qed.
+
+(** Power and nullity *)
+
+Lemma pow_eq_0 : forall a b, b~=0 -> a^b == 0 -> a == 0.
+Proof. intros. apply (pow_eq_0 a b); trivial. auto'. Qed.
+
+Lemma pow_nonzero : forall a b, a~=0 -> a^b ~= 0.
+Proof. wrap pow_nonzero. Qed.
+
+Lemma pow_eq_0_iff : forall a b, a^b == 0 <-> b~=0 /\ a==0.
+Proof.
+ intros a b. split.
+ rewrite pow_eq_0_iff. intros [H |[H H']].
+ generalize (le_0_l b); order. split; order.
+ intros (Hb,Ha). rewrite Ha. now apply pow_0_l'.
+Qed.
+
+(** Monotonicity *)
+
+Lemma pow_lt_mono_l : forall a b c, c~=0 -> a<b -> a^c < b^c.
+Proof. wrap pow_lt_mono_l. Qed.
+
+Lemma pow_le_mono_l : forall a b c, a<=b -> a^c <= b^c.
+Proof. wrap pow_le_mono_l. Qed.
+
+Lemma pow_gt_1 : forall a b, 1<a -> b~=0 -> 1<a^b.
+Proof. wrap pow_gt_1. Qed.
+
+Lemma pow_lt_mono_r : forall a b c, 1<a -> b<c -> a^b < a^c.
+Proof. wrap pow_lt_mono_r. Qed.
+
+(** NB: since 0^0 > 0^1, the following result isn't valid with a=0 *)
+
+Lemma pow_le_mono_r : forall a b c, a~=0 -> b<=c -> a^b <= a^c.
+Proof. wrap pow_le_mono_r. Qed.
+
+Lemma pow_le_mono : forall a b c d, a~=0 -> a<=c -> b<=d ->
+ a^b <= c^d.
+Proof. wrap pow_le_mono. Qed.
+
+Definition pow_lt_mono : forall a b c d, 0<a<c -> 0<b<d ->
+ a^b < c^d
+ := pow_lt_mono.
+
+(** Injectivity *)
+
+Lemma pow_inj_l : forall a b c, c~=0 -> a^c == b^c -> a == b.
+Proof. intros; eapply pow_inj_l; eauto; auto'. Qed.
+
+Lemma pow_inj_r : forall a b c, 1<a -> a^b == a^c -> b == c.
+Proof. intros; eapply pow_inj_r; eauto; auto'. Qed.
+
+(** Monotonicity results, both ways *)
+
+Lemma pow_lt_mono_l_iff : forall a b c, c~=0 ->
+ (a<b <-> a^c < b^c).
+Proof. wrap pow_lt_mono_l_iff. Qed.
+
+Lemma pow_le_mono_l_iff : forall a b c, c~=0 ->
+ (a<=b <-> a^c <= b^c).
+Proof. wrap pow_le_mono_l_iff. Qed.
+
+Lemma pow_lt_mono_r_iff : forall a b c, 1<a ->
+ (b<c <-> a^b < a^c).
+Proof. wrap pow_lt_mono_r_iff. Qed.
+
+Lemma pow_le_mono_r_iff : forall a b c, 1<a ->
+ (b<=c <-> a^b <= a^c).
+Proof. wrap pow_le_mono_r_iff. Qed.
+
+(** For any a>1, the a^x function is above the identity function *)
+
+Lemma pow_gt_lin_r : forall a b, 1<a -> b < a^b.
+Proof. wrap pow_gt_lin_r. Qed.
+
+(** Someday, we should say something about the full Newton formula.
+ In the meantime, we can at least provide some inequalities about
+ (a+b)^c.
+*)
+
+Lemma pow_add_lower : forall a b c, c~=0 ->
+ a^c + b^c <= (a+b)^c.
+Proof. wrap pow_add_lower. Qed.
+
+(** This upper bound can also be seen as a convexity proof for x^c :
+ image of (a+b)/2 is below the middle of the images of a and b
+*)
+
+Lemma pow_add_upper : forall a b c, c~=0 ->
+ (a+b)^c <= 2^(pred c) * (a^c + b^c).
+Proof. wrap pow_add_upper. Qed.
+
+(** Power and parity *)
+
+Lemma even_pow : forall a b, b~=0 -> even (a^b) = even a.
+Proof.
+ intros a b Hb. rewrite neq_0_lt_0 in Hb.
+ apply lt_ind with (4:=Hb). solve_proper.
+ now nzsimpl.
+ clear b Hb. intros b Hb IH.
+ rewrite pow_succ_r', even_mul, IH. now destruct (even a).
+Qed.
+
+Lemma odd_pow : forall a b, b~=0 -> odd (a^b) = odd a.
+Proof.
+ intros. now rewrite <- !negb_even, even_pow.
+Qed.
+
+End NPowProp.
diff --git a/theories/Numbers/Natural/Abstract/NProperties.v b/theories/Numbers/Natural/Abstract/NProperties.v
index c9e05113..1edb6b51 100644
--- a/theories/Numbers/Natural/Abstract/NProperties.v
+++ b/theories/Numbers/Natural/Abstract/NProperties.v
@@ -1,22 +1,17 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: NProperties.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
+Require Export NAxioms.
+Require Import NMaxMin NParity NPow NSqrt NLog NDiv NGcd NLcm NBits.
-Require Export NAxioms NSub.
+(** This functor summarizes all known facts about N. *)
-(** This functor summarizes all known facts about N.
- For the moment it is only an alias to [NSubPropFunct], which
- subsumes all others.
-*)
-
-Module Type NPropSig := NSubPropFunct.
-
-Module NPropFunct (N:NAxiomsSig) <: NPropSig N.
- Include NPropSig N.
-End NPropFunct.
+Module Type NProp (N:NAxiomsSig) :=
+ NMaxMinProp N <+ NParityProp N <+ NPowProp N <+ NSqrtProp N
+ <+ NLog2Prop N <+ NDivProp N <+ NGcdProp N <+ NLcmProp N
+ <+ NBitsProp N.
diff --git a/theories/Numbers/Natural/Abstract/NSqrt.v b/theories/Numbers/Natural/Abstract/NSqrt.v
new file mode 100644
index 00000000..34b7d011
--- /dev/null
+++ b/theories/Numbers/Natural/Abstract/NSqrt.v
@@ -0,0 +1,75 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(** Properties of Square Root Function *)
+
+Require Import NAxioms NSub NZSqrt.
+
+Module NSqrtProp (Import A : NAxiomsSig')(Import B : NSubProp A).
+
+ Module Import Private_NZSqrt := Nop <+ NZSqrtProp A A B.
+
+ Ltac auto' := trivial; try rewrite <- neq_0_lt_0; auto using le_0_l.
+ Ltac wrap l := intros; apply l; auto'.
+
+ (** We redefine NZSqrt's results, without the non-negative hyps *)
+
+Lemma sqrt_spec' : forall a, √a*√a <= a < S (√a) * S (√a).
+Proof. wrap sqrt_spec. Qed.
+
+Definition sqrt_unique : forall a b, b*b<=a<(S b)*(S b) -> √a == b
+ := sqrt_unique.
+
+Lemma sqrt_square : forall a, √(a*a) == a.
+Proof. wrap sqrt_square. Qed.
+
+Definition sqrt_le_mono : forall a b, a<=b -> √a <= √b
+ := sqrt_le_mono.
+
+Definition sqrt_lt_cancel : forall a b, √a < √b -> a < b
+ := sqrt_lt_cancel.
+
+Lemma sqrt_le_square : forall a b, b*b<=a <-> b <= √a.
+Proof. wrap sqrt_le_square. Qed.
+
+Lemma sqrt_lt_square : forall a b, a<b*b <-> √a < b.
+Proof. wrap sqrt_lt_square. Qed.
+
+Definition sqrt_0 := sqrt_0.
+Definition sqrt_1 := sqrt_1.
+Definition sqrt_2 := sqrt_2.
+
+Definition sqrt_lt_lin : forall a, 1<a -> √a<a
+ := sqrt_lt_lin.
+
+Lemma sqrt_le_lin : forall a, √a<=a.
+Proof. wrap sqrt_le_lin. Qed.
+
+Definition sqrt_mul_below : forall a b, √a * √b <= √(a*b)
+ := sqrt_mul_below.
+
+Lemma sqrt_mul_above : forall a b, √(a*b) < S (√a) * S (√b).
+Proof. wrap sqrt_mul_above. Qed.
+
+Lemma sqrt_succ_le : forall a, √(S a) <= S (√a).
+Proof. wrap sqrt_succ_le. Qed.
+
+Lemma sqrt_succ_or : forall a, √(S a) == S (√a) \/ √(S a) == √a.
+Proof. wrap sqrt_succ_or. Qed.
+
+Definition sqrt_add_le : forall a b, √(a+b) <= √a + √b
+ := sqrt_add_le.
+
+Lemma add_sqrt_le : forall a b, √a + √b <= √(2*(a+b)).
+Proof. wrap add_sqrt_le. Qed.
+
+(** For the moment, we include stuff about [sqrt_up] with patching them. *)
+
+Include NZSqrtUpProp A A B Private_NZSqrt.
+
+End NSqrtProp.
diff --git a/theories/Numbers/Natural/Abstract/NStrongRec.v b/theories/Numbers/Natural/Abstract/NStrongRec.v
index d9a2427d..607746d5 100644
--- a/theories/Numbers/Natural/Abstract/NStrongRec.v
+++ b/theories/Numbers/Natural/Abstract/NStrongRec.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,15 +8,15 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NStrongRec.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
(** This file defined the strong (course-of-value, well-founded) recursion
and proves its properties *)
Require Export NSub.
-Module NStrongRecPropFunct (Import N : NAxiomsSig').
-Include NSubPropFunct N.
+Ltac f_equiv' := repeat progress (f_equiv; try intros ? ? ?; auto).
+
+Module NStrongRecProp (Import N : NAxiomsRecSig').
+Include NSubProp N.
Section StrongRecursion.
@@ -51,30 +51,18 @@ Proof.
reflexivity.
Qed.
-(** We need a result similar to [f_equal], but for setoid equalities. *)
-Lemma f_equiv : forall f g x y,
- (N.eq==>Aeq)%signature f g -> N.eq x y -> Aeq (f x) (g y).
-Proof.
-auto.
-Qed.
-
Instance strong_rec0_wd :
Proper (Aeq ==> ((N.eq ==> Aeq) ==> N.eq ==> Aeq) ==> N.eq ==> N.eq ==> Aeq)
strong_rec0.
Proof.
-unfold strong_rec0.
-repeat red; intros.
-apply f_equiv; auto.
-apply recursion_wd; try red; auto.
+unfold strong_rec0; f_equiv'.
Qed.
Instance strong_rec_wd :
Proper (Aeq ==> ((N.eq ==> Aeq) ==> N.eq ==> Aeq) ==> N.eq ==> Aeq) strong_rec.
Proof.
intros a a' Eaa' f f' Eff' n n' Enn'.
-rewrite !strong_rec_alt.
-apply strong_rec0_wd; auto.
-now rewrite Enn'.
+rewrite !strong_rec_alt; f_equiv'.
Qed.
Section FixPoint.
@@ -92,18 +80,16 @@ Lemma strong_rec0_succ : forall a n m,
Aeq (strong_rec0 a f (S n) m) (f (strong_rec0 a f n) m).
Proof.
intros. unfold strong_rec0.
-apply f_equiv; auto with *.
-rewrite recursion_succ; try (repeat red; auto with *; fail).
-apply f_wd.
-apply recursion_wd; try red; auto with *.
+f_equiv.
+rewrite recursion_succ; f_equiv'.
+reflexivity.
Qed.
Lemma strong_rec_0 : forall a,
Aeq (strong_rec a f 0) (f (fun _ => a) 0).
Proof.
-intros. rewrite strong_rec_alt, strong_rec0_succ.
-apply f_wd; auto with *.
-red; intros; rewrite strong_rec0_0; auto with *.
+intros. rewrite strong_rec_alt, strong_rec0_succ; f_equiv'.
+rewrite strong_rec0_0. reflexivity.
Qed.
(* We need an assumption saying that for every n, the step function (f h n)
@@ -158,7 +144,7 @@ intros.
transitivity (f (fun n => strong_rec0 a f (S n) n) n).
rewrite strong_rec_alt.
apply strong_rec0_fixpoint.
-apply f_wd; auto with *.
+f_equiv.
intros x x' Hx; rewrite strong_rec_alt, Hx; auto with *.
Qed.
@@ -204,7 +190,7 @@ Qed.
End FixPoint.
End StrongRecursion.
-Implicit Arguments strong_rec [A].
+Arguments strong_rec [A] a f n.
-End NStrongRecPropFunct.
+End NStrongRecProp.
diff --git a/theories/Numbers/Natural/Abstract/NSub.v b/theories/Numbers/Natural/Abstract/NSub.v
index c0be3114..d7143c67 100644
--- a/theories/Numbers/Natural/Abstract/NSub.v
+++ b/theories/Numbers/Natural/Abstract/NSub.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,12 +8,10 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NSub.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Export NMulOrder.
-Module Type NSubPropFunct (Import N : NAxiomsSig').
-Include NMulOrderPropFunct N.
+Module Type NSubProp (Import N : NAxiomsMiniSig').
+Include NMulOrderProp N.
Theorem sub_0_l : forall n, 0 - n == 0.
Proof.
@@ -37,7 +35,7 @@ Qed.
Theorem sub_gt : forall n m, n > m -> n - m ~= 0.
Proof.
intros n m H; elim H using lt_ind_rel; clear n m H.
-solve_relation_wd.
+solve_proper.
intro; rewrite sub_0_r; apply neq_succ_0.
intros; now rewrite sub_succ.
Qed.
@@ -47,8 +45,8 @@ Proof.
intros n m p; induct p.
intro; now do 2 rewrite sub_0_r.
intros p IH H. do 2 rewrite sub_succ_r.
-rewrite <- IH by (apply lt_le_incl; now apply -> le_succ_l).
-rewrite add_pred_r by (apply sub_gt; now apply -> le_succ_l).
+rewrite <- IH by (apply lt_le_incl; now apply le_succ_l).
+rewrite add_pred_r by (apply sub_gt; now apply le_succ_l).
reflexivity.
Qed.
@@ -205,6 +203,26 @@ Proof.
intros n m p. rewrite add_comm; apply lt_add_lt_sub_r.
Qed.
+Theorem sub_lt : forall n m, m <= n -> 0 < m -> n - m < n.
+Proof.
+intros n m LE LT.
+assert (LE' := le_sub_l n m). rewrite lt_eq_cases in LE'.
+destruct LE' as [LT'|EQ]. assumption.
+apply add_sub_eq_nz in EQ; [|order].
+rewrite (add_lt_mono_r _ _ n), add_0_l in LT. order.
+Qed.
+
+Lemma sub_le_mono_r : forall n m p, n <= m -> n-p <= m-p.
+Proof.
+ intros. rewrite le_sub_le_add_r. transitivity m. assumption. apply sub_add_le.
+Qed.
+
+Lemma sub_le_mono_l : forall n m p, n <= m -> p-m <= p-n.
+Proof.
+ intros. rewrite le_sub_le_add_r.
+ transitivity (p-n+n); [ apply sub_add_le | now apply add_le_mono_l].
+Qed.
+
(** Sub and mul *)
Theorem mul_pred_r : forall n m, n * (P m) == n * m - n.
@@ -224,10 +242,10 @@ intros n IH. destruct (le_gt_cases m n) as [H | H].
rewrite sub_succ_l by assumption. do 2 rewrite mul_succ_l.
rewrite (add_comm ((n - m) * p) p), (add_comm (n * p) p).
rewrite <- (add_sub_assoc p (n * p) (m * p)) by now apply mul_le_mono_r.
-now apply <- add_cancel_l.
-assert (H1 : S n <= m); [now apply <- le_succ_l |].
-setoid_replace (S n - m) with 0 by now apply <- sub_0_le.
-setoid_replace ((S n * p) - m * p) with 0 by (apply <- sub_0_le; now apply mul_le_mono_r).
+now apply add_cancel_l.
+assert (H1 : S n <= m); [now apply le_succ_l |].
+setoid_replace (S n - m) with 0 by now apply sub_0_le.
+setoid_replace ((S n * p) - m * p) with 0 by (apply sub_0_le; now apply mul_le_mono_r).
apply mul_0_l.
Qed.
@@ -298,5 +316,5 @@ Theorem add_dichotomy :
forall n m, (exists p, p + n == m) \/ (exists p, p + m == n).
Proof. exact le_alt_dichotomy. Qed.
-End NSubPropFunct.
+End NSubProp.
diff --git a/theories/Numbers/Natural/BigN/BigN.v b/theories/Numbers/Natural/BigN/BigN.v
index 7c480862..7f205b38 100644
--- a/theories/Numbers/Natural/BigN/BigN.v
+++ b/theories/Numbers/Natural/BigN/BigN.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -12,7 +12,7 @@
Require Export Int31.
Require Import CyclicAxioms Cyclic31 Ring31 NSig NSigNAxioms NMake
- NProperties NDiv GenericMinMax.
+ NProperties GenericMinMax.
(** The following [BigN] module regroups both the operations and
all the abstract properties:
@@ -21,73 +21,63 @@ Require Import CyclicAxioms Cyclic31 Ring31 NSig NSigNAxioms NMake
w.r.t. ZArith
- [NTypeIsNAxioms] shows (mainly) that these operations implement
the interface [NAxioms]
- - [NPropSig] adds all generic properties derived from [NAxioms]
- - [NDivPropFunct] provides generic properties of [div] and [mod].
+ - [NProp] adds all generic properties derived from [NAxioms]
- [MinMax*Properties] provides properties of [min] and [max].
*)
-Module BigN <: NType <: OrderedTypeFull <: TotalOrder :=
- NMake.Make Int31Cyclic <+ NTypeIsNAxioms
- <+ !NPropSig <+ !NDivPropFunct <+ HasEqBool2Dec
- <+ !MinMaxLogicalProperties <+ !MinMaxDecProperties.
+Delimit Scope bigN_scope with bigN.
+Module BigN <: NType <: OrderedTypeFull <: TotalOrder.
+ Include NMake.Make Int31Cyclic [scope abstract_scope to bigN_scope].
+ Bind Scope bigN_scope with t t'.
+ Include NTypeIsNAxioms
+ <+ NProp [no inline]
+ <+ HasEqBool2Dec [no inline]
+ <+ MinMaxLogicalProperties [no inline]
+ <+ MinMaxDecProperties [no inline].
+End BigN.
+
+(** Nota concerning scopes : for the first Include, we cannot bind
+ the scope bigN_scope to a type that doesn't exists yet.
+ We hence need to explicitely declare the scope substitution.
+ For the next Include, the abstract type t (in scope abstract_scope)
+ gets substituted to concrete BigN.t (in scope bigN_scope),
+ and the corresponding argument scope are fixed automatically.
+*)
(** Notations about [BigN] *)
-Notation bigN := BigN.t.
-
-Delimit Scope bigN_scope with bigN.
-Bind Scope bigN_scope with bigN.
-Bind Scope bigN_scope with BigN.t.
-Bind Scope bigN_scope with BigN.t_.
-(* Bind Scope has no retroactive effect, let's declare scopes by hand. *)
-Arguments Scope BigN.to_Z [bigN_scope].
-Arguments Scope BigN.succ [bigN_scope].
-Arguments Scope BigN.pred [bigN_scope].
-Arguments Scope BigN.square [bigN_scope].
-Arguments Scope BigN.add [bigN_scope bigN_scope].
-Arguments Scope BigN.sub [bigN_scope bigN_scope].
-Arguments Scope BigN.mul [bigN_scope bigN_scope].
-Arguments Scope BigN.div [bigN_scope bigN_scope].
-Arguments Scope BigN.eq [bigN_scope bigN_scope].
-Arguments Scope BigN.lt [bigN_scope bigN_scope].
-Arguments Scope BigN.le [bigN_scope bigN_scope].
-Arguments Scope BigN.eq [bigN_scope bigN_scope].
-Arguments Scope BigN.compare [bigN_scope bigN_scope].
-Arguments Scope BigN.min [bigN_scope bigN_scope].
-Arguments Scope BigN.max [bigN_scope bigN_scope].
-Arguments Scope BigN.eq_bool [bigN_scope bigN_scope].
-Arguments Scope BigN.power_pos [bigN_scope positive_scope].
-Arguments Scope BigN.power [bigN_scope N_scope].
-Arguments Scope BigN.sqrt [bigN_scope].
-Arguments Scope BigN.div_eucl [bigN_scope bigN_scope].
-Arguments Scope BigN.modulo [bigN_scope bigN_scope].
-Arguments Scope BigN.gcd [bigN_scope bigN_scope].
+Local Open Scope bigN_scope.
+Notation bigN := BigN.t.
+Bind Scope bigN_scope with bigN BigN.t BigN.t'.
+Arguments BigN.N0 _%int31.
Local Notation "0" := BigN.zero : bigN_scope. (* temporary notation *)
Local Notation "1" := BigN.one : bigN_scope. (* temporary notation *)
+Local Notation "2" := BigN.two : bigN_scope. (* temporary notation *)
Infix "+" := BigN.add : bigN_scope.
Infix "-" := BigN.sub : bigN_scope.
Infix "*" := BigN.mul : bigN_scope.
Infix "/" := BigN.div : bigN_scope.
-Infix "^" := BigN.power : bigN_scope.
+Infix "^" := BigN.pow : bigN_scope.
Infix "?=" := BigN.compare : bigN_scope.
+Infix "=?" := BigN.eqb (at level 70, no associativity) : bigN_scope.
+Infix "<=?" := BigN.leb (at level 70, no associativity) : bigN_scope.
+Infix "<?" := BigN.ltb (at level 70, no associativity) : bigN_scope.
Infix "==" := BigN.eq (at level 70, no associativity) : bigN_scope.
-Notation "x != y" := (~x==y)%bigN (at level 70, no associativity) : bigN_scope.
+Notation "x != y" := (~x==y) (at level 70, no associativity) : bigN_scope.
Infix "<" := BigN.lt : bigN_scope.
Infix "<=" := BigN.le : bigN_scope.
-Notation "x > y" := (BigN.lt y x)(only parsing) : bigN_scope.
-Notation "x >= y" := (BigN.le y x)(only parsing) : bigN_scope.
-Notation "x < y < z" := (x<y /\ y<z)%bigN : bigN_scope.
-Notation "x < y <= z" := (x<y /\ y<=z)%bigN : bigN_scope.
-Notation "x <= y < z" := (x<=y /\ y<z)%bigN : bigN_scope.
-Notation "x <= y <= z" := (x<=y /\ y<=z)%bigN : bigN_scope.
+Notation "x > y" := (y < x) (only parsing) : bigN_scope.
+Notation "x >= y" := (y <= x) (only parsing) : bigN_scope.
+Notation "x < y < z" := (x<y /\ y<z) : bigN_scope.
+Notation "x < y <= z" := (x<y /\ y<=z) : bigN_scope.
+Notation "x <= y < z" := (x<=y /\ y<z) : bigN_scope.
+Notation "x <= y <= z" := (x<=y /\ y<=z) : bigN_scope.
Notation "[ i ]" := (BigN.to_Z i) : bigN_scope.
Infix "mod" := BigN.modulo (at level 40, no associativity) : bigN_scope.
-Local Open Scope bigN_scope.
-
(** Example of reasoning about [BigN] *)
Theorem succ_pred: forall q : bigN,
@@ -107,24 +97,24 @@ exact BigN.mul_1_l. exact BigN.mul_0_l. exact BigN.mul_comm.
exact BigN.mul_assoc. exact BigN.mul_add_distr_r.
Qed.
-Lemma BigNeqb_correct : forall x y, BigN.eq_bool x y = true -> x==y.
+Lemma BigNeqb_correct : forall x y, (x =? y) = true -> x==y.
Proof. now apply BigN.eqb_eq. Qed.
-Lemma BigNpower : power_theory 1 BigN.mul BigN.eq (@id N) BigN.power.
+Lemma BigNpower : power_theory 1 BigN.mul BigN.eq BigN.of_N BigN.pow.
Proof.
constructor.
-intros. red. rewrite BigN.spec_power. unfold id.
-destruct Zpower_theory as [EQ]. rewrite EQ.
+intros. red. rewrite BigN.spec_pow, BigN.spec_of_N.
+rewrite Zpower_theory.(rpow_pow_N).
destruct n; simpl. reflexivity.
induction p; simpl; intros; BigN.zify; rewrite ?IHp; auto.
Qed.
Lemma BigNdiv : div_theory BigN.eq BigN.add BigN.mul (@id _)
- (fun a b => if BigN.eq_bool b 0 then (0,a) else BigN.div_eucl a b).
+ (fun a b => if b =? 0 then (0,a) else BigN.div_eucl a b).
Proof.
constructor. unfold id. intros a b.
BigN.zify.
-generalize (Zeq_bool_if [b] 0); destruct (Zeq_bool [b] 0).
+case Z.eqb_spec.
BigN.zify. auto with zarith.
intros NEQ.
generalize (BigN.spec_div_eucl a b).
@@ -163,6 +153,7 @@ Ltac isBigNcst t :=
end
| BigN.zero => constr:true
| BigN.one => constr:true
+ | BigN.two => constr:true
| _ => constr:false
end.
@@ -172,6 +163,12 @@ Ltac BigNcst t :=
| false => constr:NotConstant
end.
+Ltac BigN_to_N t :=
+ match isBigNcst t with
+ | true => eval vm_compute in (BigN.to_N t)
+ | false => constr:NotConstant
+ end.
+
Ltac Ncst t :=
match isNcst t with
| true => constr:t
@@ -183,11 +180,11 @@ Ltac Ncst t :=
Add Ring BigNr : BigNring
(decidable BigNeqb_correct,
constants [BigNcst],
- power_tac BigNpower [Ncst],
+ power_tac BigNpower [BigN_to_N],
div BigNdiv).
Section TestRing.
-Let test : forall x y, 1 + x*y + x^2 + 1 == 1*1 + 1 + y*x + 1*x*x.
+Let test : forall x y, 1 + x*y^1 + x^2 + 1 == 1*1 + 1 + y*x + 1*x*x.
intros. ring_simplify. reflexivity.
Qed.
End TestRing.
diff --git a/theories/Numbers/Natural/BigN/NMake.v b/theories/Numbers/Natural/BigN/NMake.v
index 2b70f1bb..952f6183 100644
--- a/theories/Numbers/Natural/BigN/NMake.v
+++ b/theories/Numbers/Natural/BigN/NMake.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -16,18 +16,176 @@
representation. The representation-dependent (and macro-generated) part
is now in [NMake_gen]. *)
-Require Import BigNumPrelude ZArith CyclicAxioms.
-Require Import Nbasic Wf_nat StreamMemo NSig NMake_gen.
+Require Import Bool BigNumPrelude ZArith Nnat Ndigits CyclicAxioms DoubleType
+ Nbasic Wf_nat StreamMemo NSig NMake_gen.
-Module Make (Import W0:CyclicType) <: NType.
+Module Make (W0:CyclicType) <: NType.
- (** Macro-generated part *)
+ (** Let's include the macro-generated part. Even if we can't functorize
+ things (due to Eval red_t below), the rest of the module only uses
+ elements mentionned in interface [NAbstract]. *)
Include NMake_gen.Make W0.
+ Open Scope Z_scope.
+
+ Local Notation "[ x ]" := (to_Z x).
+
+ Definition eq (x y : t) := [x] = [y].
+
+ Declare Reduction red_t :=
+ lazy beta iota delta
+ [iter_t reduce same_level mk_t mk_t_S succ_t dom_t dom_op].
+
+ Ltac red_t :=
+ match goal with |- ?u => let v := (eval red_t in u) in change v end.
+
+ (** * Generic results *)
+
+ Tactic Notation "destr_t" constr(x) "as" simple_intropattern(pat) :=
+ destruct (destr_t x) as pat; cbv zeta;
+ rewrite ?iter_mk_t, ?spec_mk_t, ?spec_reduce.
+
+ Lemma spec_same_level : forall A (P:Z->Z->A->Prop)
+ (f : forall n, dom_t n -> dom_t n -> A),
+ (forall n x y, P (ZnZ.to_Z x) (ZnZ.to_Z y) (f n x y)) ->
+ forall x y, P [x] [y] (same_level f x y).
+ Proof.
+ intros. apply spec_same_level_dep with (P:=fun _ => P); auto.
+ Qed.
+
+ Theorem spec_pos: forall x, 0 <= [x].
+ Proof.
+ intros x. destr_t x as (n,x). now case (ZnZ.spec_to_Z x).
+ Qed.
+
+ Lemma digits_dom_op_incr : forall n m, (n<=m)%nat ->
+ (ZnZ.digits (dom_op n) <= ZnZ.digits (dom_op m))%positive.
+ Proof.
+ intros.
+ change (Zpos (ZnZ.digits (dom_op n)) <= Zpos (ZnZ.digits (dom_op m))).
+ rewrite !digits_dom_op, !Pshiftl_nat_Zpower.
+ apply Zmult_le_compat_l; auto with zarith.
+ apply Zpower_le_monotone2; auto with zarith.
+ Qed.
+
+ Definition to_N (x : t) := Z.to_N (to_Z x).
+
+ (** * Zero, One *)
+
+ Definition zero := mk_t O ZnZ.zero.
+ Definition one := mk_t O ZnZ.one.
+
+ Theorem spec_0: [zero] = 0.
+ Proof.
+ unfold zero. rewrite spec_mk_t. exact ZnZ.spec_0.
+ Qed.
+
+ Theorem spec_1: [one] = 1.
+ Proof.
+ unfold one. rewrite spec_mk_t. exact ZnZ.spec_1.
+ Qed.
+
+ (** * Successor *)
+
+ (** NB: it is crucial here and for the rest of this file to preserve
+ the let-in's. They allow to pre-compute once and for all the
+ field access to Z/nZ initial structures (when n=0..6). *)
+
+ Local Notation succn := (fun n =>
+ let op := dom_op n in
+ let succ_c := ZnZ.succ_c in
+ let one := ZnZ.one in
+ fun x => match succ_c x with
+ | C0 r => mk_t n r
+ | C1 r => mk_t_S n (WW one r)
+ end).
+
+ Definition succ : t -> t := Eval red_t in iter_t succn.
+
+ Lemma succ_fold : succ = iter_t succn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_succ: forall n, [succ n] = [n] + 1.
+ Proof.
+ intros x. rewrite succ_fold. destr_t x as (n,x).
+ generalize (ZnZ.spec_succ_c x); case ZnZ.succ_c.
+ intros. rewrite spec_mk_t. assumption.
+ intros. unfold interp_carry in *.
+ rewrite spec_mk_t_S. simpl. rewrite ZnZ.spec_1. assumption.
+ Qed.
+
+ (** Two *)
+
+ (** Not really pretty, but since W0 might be Z/2Z, we're not sure
+ there's a proper 2 there. *)
+
+ Definition two := succ one.
+
+ Lemma spec_2 : [two] = 2.
+ Proof.
+ unfold two. now rewrite spec_succ, spec_1.
+ Qed.
+
+ (** * Addition *)
+
+ Local Notation addn := (fun n =>
+ let op := dom_op n in
+ let add_c := ZnZ.add_c in
+ let one := ZnZ.one in
+ fun x y =>match add_c x y with
+ | C0 r => mk_t n r
+ | C1 r => mk_t_S n (WW one r)
+ end).
+
+ Definition add : t -> t -> t := Eval red_t in same_level addn.
+
+ Lemma add_fold : add = same_level addn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_add: forall x y, [add x y] = [x] + [y].
+ Proof.
+ intros x y. rewrite add_fold. apply spec_same_level; clear x y.
+ intros n x y. simpl.
+ generalize (ZnZ.spec_add_c x y); case ZnZ.add_c; intros z H.
+ rewrite spec_mk_t. assumption.
+ rewrite spec_mk_t_S. unfold interp_carry in H.
+ simpl. rewrite ZnZ.spec_1. assumption.
+ Qed.
(** * Predecessor *)
+ Local Notation predn := (fun n =>
+ let pred_c := ZnZ.pred_c in
+ fun x => match pred_c x with
+ | C0 r => reduce n r
+ | C1 _ => zero
+ end).
+
+ Definition pred : t -> t := Eval red_t in iter_t predn.
+
+ Lemma pred_fold : pred = iter_t predn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_pred_pos : forall x, 0 < [x] -> [pred x] = [x] - 1.
+ Proof.
+ intros x. rewrite pred_fold. destr_t x as (n,x). intros H.
+ generalize (ZnZ.spec_pred_c x); case ZnZ.pred_c; intros y H'.
+ rewrite spec_reduce. assumption.
+ exfalso. unfold interp_carry in *.
+ generalize (ZnZ.spec_to_Z x) (ZnZ.spec_to_Z y); auto with zarith.
+ Qed.
+
+ Theorem spec_pred0 : forall x, [x] = 0 -> [pred x] = 0.
+ Proof.
+ intros x. rewrite pred_fold. destr_t x as (n,x). intros H.
+ generalize (ZnZ.spec_pred_c x); case ZnZ.pred_c; intros y H'.
+ rewrite spec_reduce.
+ unfold interp_carry in H'.
+ generalize (ZnZ.spec_to_Z y); auto with zarith.
+ exact spec_0.
+ Qed.
+
Lemma spec_pred : forall x, [pred x] = Zmax 0 ([x]-1).
Proof.
intros. destruct (Zle_lt_or_eq _ _ (spec_pos x)).
@@ -36,9 +194,42 @@ Module Make (Import W0:CyclicType) <: NType.
rewrite <- H; apply spec_pred0; auto.
Qed.
-
(** * Subtraction *)
+ Local Notation subn := (fun n =>
+ let sub_c := ZnZ.sub_c in
+ fun x y => match sub_c x y with
+ | C0 r => reduce n r
+ | C1 r => zero
+ end).
+
+ Definition sub : t -> t -> t := Eval red_t in same_level subn.
+
+ Lemma sub_fold : sub = same_level subn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_sub_pos : forall x y, [y] <= [x] -> [sub x y] = [x] - [y].
+ Proof.
+ intros x y. rewrite sub_fold. apply spec_same_level. clear x y.
+ intros n x y. simpl.
+ generalize (ZnZ.spec_sub_c x y); case ZnZ.sub_c; intros z H LE.
+ rewrite spec_reduce. assumption.
+ unfold interp_carry in H.
+ exfalso.
+ generalize (ZnZ.spec_to_Z z); auto with zarith.
+ Qed.
+
+ Theorem spec_sub0 : forall x y, [x] < [y] -> [sub x y] = 0.
+ Proof.
+ intros x y. rewrite sub_fold. apply spec_same_level. clear x y.
+ intros n x y. simpl.
+ generalize (ZnZ.spec_sub_c x y); case ZnZ.sub_c; intros z H LE.
+ rewrite spec_reduce.
+ unfold interp_carry in H.
+ generalize (ZnZ.spec_to_Z z); auto with zarith.
+ exact spec_0.
+ Qed.
+
Lemma spec_sub : forall x y, [sub x y] = Zmax 0 ([x]-[y]).
Proof.
intros. destruct (Zle_or_lt [y] [x]).
@@ -48,35 +239,112 @@ Module Make (Import W0:CyclicType) <: NType.
(** * Comparison *)
- Theorem spec_compare : forall x y, compare x y = Zcompare [x] [y].
+ Definition comparen_m n :
+ forall m, word (dom_t n) (S m) -> dom_t n -> comparison :=
+ let op := dom_op n in
+ let zero := @ZnZ.zero _ op in
+ let compare := @ZnZ.compare _ op in
+ let compare0 := compare zero in
+ fun m => compare_mn_1 (dom_t n) (dom_t n) zero compare compare0 compare (S m).
+
+ Let spec_comparen_m:
+ forall n m (x : word (dom_t n) (S m)) (y : dom_t n),
+ comparen_m n m x y = Zcompare (eval n (S m) x) (ZnZ.to_Z y).
+ Proof.
+ intros n m x y.
+ unfold comparen_m, eval.
+ rewrite nmake_double.
+ apply spec_compare_mn_1.
+ exact ZnZ.spec_0.
+ intros. apply ZnZ.spec_compare.
+ exact ZnZ.spec_to_Z.
+ exact ZnZ.spec_compare.
+ exact ZnZ.spec_compare.
+ exact ZnZ.spec_to_Z.
+ Qed.
+
+ Definition comparenm n m wx wy :=
+ let mn := Max.max n m in
+ let d := diff n m in
+ let op := make_op mn in
+ ZnZ.compare
+ (castm (diff_r n m) (extend_tr wx (snd d)))
+ (castm (diff_l n m) (extend_tr wy (fst d))).
+
+ Local Notation compare_folded :=
+ (iter_sym _
+ (fun n => @ZnZ.compare _ (dom_op n))
+ comparen_m
+ comparenm
+ CompOpp).
+
+ Definition compare : t -> t -> comparison :=
+ Eval lazy beta iota delta [iter_sym dom_op dom_t comparen_m] in
+ compare_folded.
+
+ Lemma compare_fold : compare = compare_folded.
Proof.
- intros x y. generalize (spec_compare_aux x y); destruct compare;
- intros; symmetry; try rewrite Zcompare_Eq_iff_eq; assumption.
+ lazy beta iota delta [iter_sym dom_op dom_t comparen_m]. reflexivity.
Qed.
- Definition eq_bool x y :=
+(** TODO: no need for ZnZ.Spec_rect , Spec_ind, and so on... *)
+
+ Theorem spec_compare : forall x y,
+ compare x y = Zcompare [x] [y].
+ Proof.
+ intros x y. rewrite compare_fold. apply spec_iter_sym; clear x y.
+ intros. apply ZnZ.spec_compare.
+ intros. cbv beta zeta. apply spec_comparen_m.
+ intros n m x y; unfold comparenm.
+ rewrite (spec_cast_l n m x), (spec_cast_r n m y).
+ unfold to_Z; apply ZnZ.spec_compare.
+ intros. subst. apply Zcompare_antisym.
+ Qed.
+
+ Definition eqb (x y : t) : bool :=
match compare x y with
| Eq => true
| _ => false
end.
- Theorem spec_eq_bool : forall x y, eq_bool x y = Zeq_bool [x] [y].
+ Theorem spec_eqb x y : eqb x y = Z.eqb [x] [y].
Proof.
- intros. unfold eq_bool, Zeq_bool. rewrite spec_compare; reflexivity.
+ apply eq_iff_eq_true.
+ unfold eqb. rewrite Z.eqb_eq, <- Z.compare_eq_iff, spec_compare.
+ split; [now destruct Z.compare | now intros ->].
Qed.
- Theorem spec_eq_bool_aux: forall x y,
- if eq_bool x y then [x] = [y] else [x] <> [y].
+ Definition lt (n m : t) := [n] < [m].
+ Definition le (n m : t) := [n] <= [m].
+
+ Definition ltb (x y : t) : bool :=
+ match compare x y with
+ | Lt => true
+ | _ => false
+ end.
+
+ Theorem spec_ltb x y : ltb x y = Z.ltb [x] [y].
Proof.
- intros x y; unfold eq_bool.
- generalize (spec_compare_aux x y); case compare; auto with zarith.
+ apply eq_iff_eq_true.
+ rewrite Z.ltb_lt. unfold Z.lt, ltb. rewrite spec_compare.
+ split; [now destruct Z.compare | now intros ->].
Qed.
- Definition lt n m := [n] < [m].
- Definition le n m := [n] <= [m].
+ Definition leb (x y : t) : bool :=
+ match compare x y with
+ | Gt => false
+ | _ => true
+ end.
+
+ Theorem spec_leb x y : leb x y = Z.leb [x] [y].
+ Proof.
+ apply eq_iff_eq_true.
+ rewrite Z.leb_le. unfold Z.le, leb. rewrite spec_compare.
+ destruct Z.compare; split; try easy. now destruct 1.
+ Qed.
- Definition min n m := match compare n m with Gt => m | _ => n end.
- Definition max n m := match compare n m with Lt => m | _ => n end.
+ Definition min (n m : t) : t := match compare n m with Gt => m | _ => n end.
+ Definition max (n m : t) : t := match compare n m with Lt => m | _ => n end.
Theorem spec_max : forall n m, [max n m] = Zmax [n] [m].
Proof.
@@ -88,46 +356,239 @@ Module Make (Import W0:CyclicType) <: NType.
intros. unfold min, Zmin. rewrite spec_compare; destruct Zcompare; reflexivity.
Qed.
+ (** * Multiplication *)
+
+ Definition wn_mul n : forall m, word (dom_t n) (S m) -> dom_t n -> t :=
+ let op := dom_op n in
+ let zero := @ZnZ.zero _ op in
+ let succ := @ZnZ.succ _ op in
+ let add_c := @ZnZ.add_c _ op in
+ let mul_c := @ZnZ.mul_c _ op in
+ let ww := @ZnZ.WW _ op in
+ let ow := @ZnZ.OW _ op in
+ let eq0 := @ZnZ.eq0 _ op in
+ let mul_add := @DoubleMul.w_mul_add _ zero succ add_c mul_c in
+ let mul_add_n1 := @DoubleMul.double_mul_add_n1 _ zero ww ow mul_add in
+ fun m x y =>
+ let (w,r) := mul_add_n1 (S m) x y zero in
+ if eq0 w then mk_t_w' n m r
+ else mk_t_w' n (S m) (WW (extend n m w) r).
+
+ Definition mulnm n m x y :=
+ let mn := Max.max n m in
+ let d := diff n m in
+ let op := make_op mn in
+ reduce_n (S mn) (ZnZ.mul_c
+ (castm (diff_r n m) (extend_tr x (snd d)))
+ (castm (diff_l n m) (extend_tr y (fst d)))).
+
+ Local Notation mul_folded :=
+ (iter_sym _
+ (fun n => let mul_c := ZnZ.mul_c in
+ fun x y => reduce (S n) (succ_t _ (mul_c x y)))
+ wn_mul
+ mulnm
+ (fun x => x)).
+
+ Definition mul : t -> t -> t :=
+ Eval lazy beta iota delta
+ [iter_sym dom_op dom_t reduce succ_t extend zeron
+ wn_mul DoubleMul.w_mul_add mk_t_w'] in
+ mul_folded.
+
+ Lemma mul_fold : mul = mul_folded.
+ Proof.
+ lazy beta iota delta
+ [iter_sym dom_op dom_t reduce succ_t extend zeron
+ wn_mul DoubleMul.w_mul_add mk_t_w']. reflexivity.
+ Qed.
- (** * Power *)
+ Lemma spec_muln:
+ forall n (x: word _ (S n)) y,
+ [Nn (S n) (ZnZ.mul_c (Ops:=make_op n) x y)] = [Nn n x] * [Nn n y].
+ Proof.
+ intros n x y; unfold to_Z.
+ rewrite <- ZnZ.spec_mul_c.
+ rewrite make_op_S.
+ case ZnZ.mul_c; auto.
+ Qed.
- 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.
+ Lemma spec_mul_add_n1: forall n m x y z,
+ let (q,r) := DoubleMul.double_mul_add_n1 ZnZ.zero ZnZ.WW ZnZ.OW
+ (DoubleMul.w_mul_add ZnZ.zero ZnZ.succ ZnZ.add_c ZnZ.mul_c)
+ (S m) x y z in
+ ZnZ.to_Z q * (base (ZnZ.digits (nmake_op _ (dom_op n) (S m))))
+ + eval n (S m) r =
+ eval n (S m) x * ZnZ.to_Z y + ZnZ.to_Z z.
+ Proof.
+ intros n m x y z.
+ rewrite digits_nmake.
+ unfold eval. rewrite nmake_double.
+ apply DoubleMul.spec_double_mul_add_n1.
+ apply ZnZ.spec_0.
+ exact ZnZ.spec_WW.
+ exact ZnZ.spec_OW.
+ apply DoubleCyclic.spec_mul_add.
+ Qed.
- Theorem spec_power_pos: forall x n, [power_pos x n] = [x] ^ Zpos n.
+ Lemma spec_wn_mul : forall n m x y,
+ [wn_mul n m x y] = (eval n (S m) x) * ZnZ.to_Z y.
Proof.
- intros x n; generalize x; elim n; clear n x; simpl power_pos.
- intros; rewrite spec_mul; rewrite spec_square; rewrite H.
- rewrite Zpos_xI; rewrite Zpower_exp; auto with zarith.
- rewrite (Zmult_comm 2); rewrite Zpower_mult; auto with zarith.
- rewrite Zpower_2; rewrite Zpower_1_r; auto.
- intros; rewrite spec_square; rewrite H.
- rewrite Zpos_xO; auto with zarith.
- rewrite (Zmult_comm 2); rewrite Zpower_mult; auto with zarith.
- rewrite Zpower_2; auto.
- intros; rewrite Zpower_1_r; auto.
+ intros; unfold wn_mul.
+ generalize (spec_mul_add_n1 n m x y ZnZ.zero).
+ case DoubleMul.double_mul_add_n1; intros q r Hqr.
+ rewrite ZnZ.spec_0, Zplus_0_r in Hqr. rewrite <- Hqr.
+ generalize (ZnZ.spec_eq0 q); case ZnZ.eq0; intros HH.
+ rewrite HH; auto. simpl. apply spec_mk_t_w'.
+ clear.
+ rewrite spec_mk_t_w'.
+ set (m' := S m) in *.
+ unfold eval.
+ rewrite nmake_WW. f_equal. f_equal.
+ rewrite <- spec_mk_t.
+ symmetry. apply spec_extend.
Qed.
- Definition power x (n:N) := match n with
- | BinNat.N0 => one
- | BinNat.Npos p => power_pos x p
- end.
+ Theorem spec_mul : forall x y, [mul x y] = [x] * [y].
+ Proof.
+ intros x y. rewrite mul_fold. apply spec_iter_sym; clear x y.
+ intros n x y. cbv zeta beta.
+ rewrite spec_reduce, spec_succ_t, <- ZnZ.spec_mul_c; auto.
+ apply spec_wn_mul.
+ intros n m x y; unfold mulnm. rewrite spec_reduce_n.
+ rewrite (spec_cast_l n m x), (spec_cast_r n m y).
+ apply spec_muln.
+ intros. rewrite Zmult_comm; auto.
+ Qed.
- Theorem spec_power: forall x n, [power x n] = [x] ^ Z_of_N n.
+ (** * Division by a smaller number *)
+
+ Definition wn_divn1 n :=
+ let op := dom_op n in
+ let zd := ZnZ.zdigits op in
+ let zero := @ZnZ.zero _ op in
+ let ww := @ZnZ.WW _ op in
+ let head0 := @ZnZ.head0 _ op in
+ let add_mul_div := @ZnZ.add_mul_div _ op in
+ let div21 := @ZnZ.div21 _ op in
+ let compare := @ZnZ.compare _ op in
+ let sub := @ZnZ.sub _ op in
+ let ddivn1 :=
+ DoubleDivn1.double_divn1 zd zero ww head0 add_mul_div div21 compare sub in
+ fun m x y => let (u,v) := ddivn1 (S m) x y in (mk_t_w' n m u, mk_t n v).
+
+ Let div_gtnm n m wx wy :=
+ let mn := Max.max n m in
+ let d := diff n m in
+ let op := make_op mn in
+ let (q, r):= ZnZ.div_gt
+ (castm (diff_r n m) (extend_tr wx (snd d)))
+ (castm (diff_l n m) (extend_tr wy (fst d))) in
+ (reduce_n mn q, reduce_n mn r).
+
+ Local Notation div_gt_folded :=
+ (iter _
+ (fun n => let div_gt := ZnZ.div_gt in
+ fun x y => let (u,v) := div_gt x y in (reduce n u, reduce n v))
+ (fun n =>
+ let div_gt := ZnZ.div_gt in
+ fun m x y =>
+ let y' := DoubleBase.get_low (zeron n) (S m) y in
+ let (u,v) := div_gt x y' in (reduce n u, reduce n v))
+ wn_divn1
+ div_gtnm).
+
+ Definition div_gt :=
+ Eval lazy beta iota delta
+ [iter dom_op dom_t reduce zeron wn_divn1 mk_t_w' mk_t] in
+ div_gt_folded.
+
+ Lemma div_gt_fold : div_gt = div_gt_folded.
Proof.
- destruct n; simpl. apply (spec_1 w0_spec).
- apply spec_power_pos.
+ lazy beta iota delta [iter dom_op dom_t reduce zeron wn_divn1 mk_t_w' mk_t].
+ reflexivity.
Qed.
+ Lemma spec_get_endn: forall n m x y,
+ eval n m x <= [mk_t n y] ->
+ [mk_t n (DoubleBase.get_low (zeron n) m x)] = eval n m x.
+ Proof.
+ intros n m x y H.
+ unfold eval. rewrite nmake_double.
+ rewrite spec_mk_t in *.
+ apply DoubleBase.spec_get_low.
+ apply spec_zeron.
+ exact ZnZ.spec_to_Z.
+ apply Zle_lt_trans with (ZnZ.to_Z y); auto.
+ rewrite <- nmake_double; auto.
+ case (ZnZ.spec_to_Z y); auto.
+ Qed.
- (** * Div *)
+ Let spec_divn1 n :=
+ DoubleDivn1.spec_double_divn1
+ (ZnZ.zdigits (dom_op n)) (ZnZ.zero:dom_t n)
+ ZnZ.WW ZnZ.head0
+ ZnZ.add_mul_div ZnZ.div21
+ ZnZ.compare ZnZ.sub ZnZ.to_Z
+ ZnZ.spec_to_Z
+ ZnZ.spec_zdigits
+ ZnZ.spec_0 ZnZ.spec_WW ZnZ.spec_head0
+ ZnZ.spec_add_mul_div ZnZ.spec_div21
+ ZnZ.spec_compare ZnZ.spec_sub.
+
+ Lemma spec_div_gt_aux : forall x y, [x] > [y] -> 0 < [y] ->
+ let (q,r) := div_gt x y in
+ [x] = [q] * [y] + [r] /\ 0 <= [r] < [y].
+ Proof.
+ intros x y. rewrite div_gt_fold. apply spec_iter; clear x y.
+ intros n x y H1 H2. simpl.
+ generalize (ZnZ.spec_div_gt x y H1 H2); case ZnZ.div_gt.
+ intros u v. rewrite 2 spec_reduce. auto.
+ intros n m x y H1 H2. cbv zeta beta.
+ generalize (ZnZ.spec_div_gt x
+ (DoubleBase.get_low (zeron n) (S m) y)).
+ case ZnZ.div_gt.
+ intros u v H3; repeat rewrite spec_reduce.
+ generalize (spec_get_endn n (S m) y x). rewrite !spec_mk_t. intros H4.
+ rewrite H4 in H3; auto with zarith.
+ intros n m x y H1 H2.
+ generalize (spec_divn1 n (S m) x y H2).
+ unfold wn_divn1; case DoubleDivn1.double_divn1.
+ intros u v H3.
+ rewrite spec_mk_t_w', spec_mk_t.
+ rewrite <- !nmake_double in H3; auto.
+ intros n m x y H1 H2; unfold div_gtnm.
+ generalize (ZnZ.spec_div_gt
+ (castm (diff_r n m)
+ (extend_tr x (snd (diff n m))))
+ (castm (diff_l n m)
+ (extend_tr y (fst (diff n m))))).
+ case ZnZ.div_gt.
+ intros xx yy HH.
+ repeat rewrite spec_reduce_n.
+ rewrite (spec_cast_l n m x), (spec_cast_r n m y).
+ unfold to_Z; apply HH.
+ rewrite (spec_cast_l n m x) in H1; auto.
+ rewrite (spec_cast_r n m y) in H1; auto.
+ rewrite (spec_cast_r n m y) in H2; auto.
+ Qed.
+
+ Theorem spec_div_gt: forall x y, [x] > [y] -> 0 < [y] ->
+ let (q,r) := div_gt x y in
+ [q] = [x] / [y] /\ [r] = [x] mod [y].
+ Proof.
+ intros x y H1 H2; generalize (spec_div_gt_aux x y H1 H2); case div_gt.
+ intros q r (H3, H4); split.
+ apply (Zdiv_unique [x] [y] [q] [r]); auto.
+ rewrite Zmult_comm; auto.
+ apply (Zmod_unique [x] [y] [q] [r]); auto.
+ rewrite Zmult_comm; auto.
+ Qed.
- Definition div_eucl x y :=
- if eq_bool y zero then (zero,zero) else
+ (** * General Division *)
+
+ Definition div_eucl (x y : t) : t * t :=
+ if eqb y zero then (zero,zero) else
match compare x y with
| Eq => (one, zero)
| Lt => (zero, x)
@@ -138,32 +599,27 @@ Module Make (Import W0:CyclicType) <: NType.
let (q,r) := div_eucl x y in
([q], [r]) = Zdiv_eucl [x] [y].
Proof.
- assert (F0: [zero] = 0).
- exact (spec_0 w0_spec).
- assert (F1: [one] = 1).
- exact (spec_1 w0_spec).
intros x y. unfold div_eucl.
- generalize (spec_eq_bool_aux y zero). destruct eq_bool; rewrite F0.
- intro H. rewrite H. destruct [x]; auto.
- intro H'.
- assert (0 < [y]) by (generalize (spec_pos y); auto with zarith).
+ rewrite spec_eqb, spec_compare, spec_0.
+ case Z.eqb_spec.
+ intros ->. rewrite spec_0. destruct [x]; auto.
+ intros H'.
+ assert (H : 0 < [y]) by (generalize (spec_pos y); auto with zarith).
clear H'.
- generalize (spec_compare_aux x y); case compare; try rewrite F0;
- try rewrite F1; intros; auto with zarith.
- rewrite H0; generalize (Z_div_same [y] (Zlt_gt _ _ H))
- (Z_mod_same [y] (Zlt_gt _ _ H));
+ case Zcompare_spec; intros Cmp;
+ rewrite ?spec_0, ?spec_1; intros; auto with zarith.
+ rewrite Cmp; generalize (Z_div_same [y] (Zlt_gt _ _ H))
+ (Z_mod_same [y] (Zlt_gt _ _ H));
unfold Zdiv, Zmod; case Zdiv_eucl; intros; subst; auto.
- assert (F2: 0 <= [x] < [y]).
- generalize (spec_pos x); auto.
- generalize (Zdiv_small _ _ F2)
- (Zmod_small _ _ F2);
+ assert (LeLt: 0 <= [x] < [y]) by (generalize (spec_pos x); auto).
+ generalize (Zdiv_small _ _ LeLt) (Zmod_small _ _ LeLt);
unfold Zdiv, Zmod; case Zdiv_eucl; intros; subst; auto.
- generalize (spec_div_gt _ _ H0 H); auto.
+ generalize (spec_div_gt _ _ (Zlt_gt _ _ Cmp) H); auto.
unfold Zdiv, Zmod; case Zdiv_eucl; case div_gt.
intros a b c d (H1, H2); subst; auto.
Qed.
- Definition div x y := fst (div_eucl x y).
+ Definition div (x y : t) : t := fst (div_eucl x y).
Theorem spec_div:
forall x y, [div x y] = [x] / [y].
@@ -174,11 +630,90 @@ Module Make (Import W0:CyclicType) <: NType.
injection H; auto.
Qed.
+ (** * Modulo by a smaller number *)
+
+ Definition wn_modn1 n :=
+ let op := dom_op n in
+ let zd := ZnZ.zdigits op in
+ let zero := @ZnZ.zero _ op in
+ let head0 := @ZnZ.head0 _ op in
+ let add_mul_div := @ZnZ.add_mul_div _ op in
+ let div21 := @ZnZ.div21 _ op in
+ let compare := @ZnZ.compare _ op in
+ let sub := @ZnZ.sub _ op in
+ let dmodn1 :=
+ DoubleDivn1.double_modn1 zd zero head0 add_mul_div div21 compare sub in
+ fun m x y => reduce n (dmodn1 (S m) x y).
+
+ Let mod_gtnm n m wx wy :=
+ let mn := Max.max n m in
+ let d := diff n m in
+ let op := make_op mn in
+ reduce_n mn (ZnZ.modulo_gt
+ (castm (diff_r n m) (extend_tr wx (snd d)))
+ (castm (diff_l n m) (extend_tr wy (fst d)))).
+
+ Local Notation mod_gt_folded :=
+ (iter _
+ (fun n => let modulo_gt := ZnZ.modulo_gt in
+ fun x y => reduce n (modulo_gt x y))
+ (fun n => let modulo_gt := ZnZ.modulo_gt in
+ fun m x y =>
+ reduce n (modulo_gt x (DoubleBase.get_low (zeron n) (S m) y)))
+ wn_modn1
+ mod_gtnm).
+
+ Definition mod_gt :=
+ Eval lazy beta iota delta [iter dom_op dom_t reduce wn_modn1 zeron] in
+ mod_gt_folded.
+
+ Lemma mod_gt_fold : mod_gt = mod_gt_folded.
+ Proof.
+ lazy beta iota delta [iter dom_op dom_t reduce wn_modn1 zeron].
+ reflexivity.
+ Qed.
+
+ Let spec_modn1 n :=
+ DoubleDivn1.spec_double_modn1
+ (ZnZ.zdigits (dom_op n)) (ZnZ.zero:dom_t n)
+ ZnZ.WW ZnZ.head0
+ ZnZ.add_mul_div ZnZ.div21
+ ZnZ.compare ZnZ.sub ZnZ.to_Z
+ ZnZ.spec_to_Z
+ ZnZ.spec_zdigits
+ ZnZ.spec_0 ZnZ.spec_WW ZnZ.spec_head0
+ ZnZ.spec_add_mul_div ZnZ.spec_div21
+ ZnZ.spec_compare ZnZ.spec_sub.
+
+ Theorem spec_mod_gt:
+ forall x y, [x] > [y] -> 0 < [y] -> [mod_gt x y] = [x] mod [y].
+ Proof.
+ intros x y. rewrite mod_gt_fold. apply spec_iter; clear x y.
+ intros n x y H1 H2. simpl. rewrite spec_reduce.
+ exact (ZnZ.spec_modulo_gt x y H1 H2).
+ intros n m x y H1 H2. cbv zeta beta. rewrite spec_reduce.
+ rewrite <- spec_mk_t in H1.
+ rewrite <- (spec_get_endn n (S m) y x); auto with zarith.
+ rewrite spec_mk_t.
+ apply ZnZ.spec_modulo_gt; auto.
+ rewrite <- (spec_get_endn n (S m) y x), !spec_mk_t in H1; auto with zarith.
+ rewrite <- (spec_get_endn n (S m) y x), !spec_mk_t in H2; auto with zarith.
+ intros n m x y H1 H2. unfold wn_modn1. rewrite spec_reduce.
+ unfold eval; rewrite nmake_double.
+ apply (spec_modn1 n); auto.
+ intros n m x y H1 H2; unfold mod_gtnm.
+ repeat rewrite spec_reduce_n.
+ rewrite (spec_cast_l n m x), (spec_cast_r n m y).
+ unfold to_Z; apply ZnZ.spec_modulo_gt.
+ rewrite (spec_cast_l n m x) in H1; auto.
+ rewrite (spec_cast_r n m y) in H1; auto.
+ rewrite (spec_cast_r n m y) in H2; auto.
+ Qed.
- (** * Modulo *)
+ (** * General Modulo *)
- Definition modulo x y :=
- if eq_bool y zero then zero else
+ Definition modulo (x y : t) : t :=
+ if eqb y zero then zero else
match compare x y with
| Eq => zero
| Lt => x
@@ -188,24 +723,129 @@ Module Make (Import W0:CyclicType) <: NType.
Theorem spec_modulo:
forall x y, [modulo x y] = [x] mod [y].
Proof.
- assert (F0: [zero] = 0).
- exact (spec_0 w0_spec).
- assert (F1: [one] = 1).
- exact (spec_1 w0_spec).
intros x y. unfold modulo.
- generalize (spec_eq_bool_aux y zero). destruct eq_bool; rewrite F0.
- intro H; rewrite H. destruct [x]; auto.
+ rewrite spec_eqb, spec_compare, spec_0.
+ case Z.eqb_spec.
+ intros ->; rewrite spec_0. destruct [x]; auto.
intro H'.
assert (H : 0 < [y]) by (generalize (spec_pos y); auto with zarith).
clear H'.
- generalize (spec_compare_aux x y); case compare; try rewrite F0;
- try rewrite F1; intros; try split; auto with zarith.
+ case Zcompare_spec;
+ rewrite ?spec_0, ?spec_1; intros; try split; auto with zarith.
rewrite H0; apply sym_equal; apply Z_mod_same; auto with zarith.
apply sym_equal; apply Zmod_small; auto with zarith.
generalize (spec_pos x); auto with zarith.
- apply spec_mod_gt; auto.
+ apply spec_mod_gt; auto with zarith.
+ Qed.
+
+ (** * Square *)
+
+ Local Notation squaren := (fun n =>
+ let square_c := ZnZ.square_c in
+ fun x => reduce (S n) (succ_t _ (square_c x))).
+
+ Definition square : t -> t := Eval red_t in iter_t squaren.
+
+ Lemma square_fold : square = iter_t squaren.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_square: forall x, [square x] = [x] * [x].
+ Proof.
+ intros x. rewrite square_fold. destr_t x as (n,x).
+ rewrite spec_succ_t. exact (ZnZ.spec_square_c x).
+ Qed.
+
+ (** * Square Root *)
+
+ Local Notation sqrtn := (fun n =>
+ let sqrt := ZnZ.sqrt in
+ fun x => reduce n (sqrt x)).
+
+ Definition sqrt : t -> t := Eval red_t in iter_t sqrtn.
+
+ Lemma sqrt_fold : sqrt = iter_t sqrtn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_sqrt_aux: forall x, [sqrt x] ^ 2 <= [x] < ([sqrt x] + 1) ^ 2.
+ Proof.
+ intros x. rewrite sqrt_fold. destr_t x as (n,x). exact (ZnZ.spec_sqrt x).
+ Qed.
+
+ Theorem spec_sqrt: forall x, [sqrt x] = Z.sqrt [x].
+ Proof.
+ intros x.
+ symmetry. apply Z.sqrt_unique.
+ rewrite <- ! Zpower_2. apply spec_sqrt_aux.
+ Qed.
+
+ (** * Power *)
+
+ Fixpoint pow_pos (x:t)(p:positive) : t :=
+ match p with
+ | xH => x
+ | xO p => square (pow_pos x p)
+ | xI p => mul (square (pow_pos x p)) x
+ end.
+
+ Theorem spec_pow_pos: forall x n, [pow_pos x n] = [x] ^ Zpos n.
+ Proof.
+ intros x n; generalize x; elim n; clear n x; simpl pow_pos.
+ intros; rewrite spec_mul; rewrite spec_square; rewrite H.
+ rewrite Zpos_xI; rewrite Zpower_exp; auto with zarith.
+ rewrite (Zmult_comm 2); rewrite Zpower_mult; auto with zarith.
+ rewrite Zpower_2; rewrite Zpower_1_r; auto.
+ intros; rewrite spec_square; rewrite H.
+ rewrite Zpos_xO; auto with zarith.
+ rewrite (Zmult_comm 2); rewrite Zpower_mult; auto with zarith.
+ rewrite Zpower_2; auto.
+ intros; rewrite Zpower_1_r; auto.
Qed.
+ Definition pow_N (x:t)(n:N) : t := match n with
+ | BinNat.N0 => one
+ | BinNat.Npos p => pow_pos x p
+ end.
+
+ Theorem spec_pow_N: forall x n, [pow_N x n] = [x] ^ Z_of_N n.
+ Proof.
+ destruct n; simpl. apply spec_1.
+ apply spec_pow_pos.
+ Qed.
+
+ Definition pow (x y:t) : t := pow_N x (to_N y).
+
+ Theorem spec_pow : forall x y, [pow x y] = [x] ^ [y].
+ Proof.
+ intros. unfold pow, to_N.
+ now rewrite spec_pow_N, Z2N.id by apply spec_pos.
+ Qed.
+
+
+ (** * digits
+
+ Number of digits in the representation of a numbers
+ (including head zero's).
+ NB: This function isn't a morphism for setoid [eq].
+ *)
+
+ Local Notation digitsn := (fun n =>
+ let digits := ZnZ.digits (dom_op n) in
+ fun _ => digits).
+
+ Definition digits : t -> positive := Eval red_t in iter_t digitsn.
+
+ Lemma digits_fold : digits = iter_t digitsn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_digits: forall x, 0 <= [x] < 2 ^ Zpos (digits x).
+ Proof.
+ intros x. rewrite digits_fold. destr_t x as (n,x). exact (ZnZ.spec_to_Z x).
+ Qed.
+
+ Lemma digits_level : forall x, digits x = ZnZ.digits (dom_op (level x)).
+ Proof.
+ intros x. rewrite digits_fold. unfold level. destr_t x as (n,x). reflexivity.
+ Qed.
(** * Gcd *)
@@ -226,15 +866,12 @@ Module Make (Import W0:CyclicType) <: NType.
Zis_gcd [a1] [b1] [cont a1 b1]) ->
Zis_gcd [a] [b] [gcd_gt_body a b cont].
Proof.
- assert (F1: [zero] = 0).
- unfold zero, w_0, to_Z; rewrite (spec_0 w0_spec); auto.
intros a b cont p H2 H3 H4; unfold gcd_gt_body.
- generalize (spec_compare_aux b zero); case compare; try rewrite F1.
- intros HH; rewrite HH; apply Zis_gcd_0.
+ rewrite ! spec_compare, spec_0. case Zcompare_spec.
+ intros ->; apply Zis_gcd_0.
intros HH; absurd (0 <= [b]); auto with zarith.
case (spec_digits b); auto with zarith.
- intros H5; generalize (spec_compare_aux (mod_gt a b) zero);
- case compare; try rewrite F1.
+ intros H5; case Zcompare_spec.
intros H6; rewrite <- (Zmult_1_r [b]).
rewrite (Z_div_mod_eq [a] [b]); auto with zarith.
rewrite <- spec_mod_gt; auto with zarith.
@@ -273,7 +910,7 @@ Module Make (Import W0:CyclicType) <: NType.
intros HH; generalize H3; rewrite <- HH; simpl Zpower; auto with zarith.
Qed.
- Fixpoint gcd_gt_aux (p:positive) (cont:t->t->t) (a b:t) {struct p} : t :=
+ Fixpoint gcd_gt_aux (p:positive) (cont:t->t->t) (a b:t) : t :=
gcd_gt_body a b
(fun a b =>
match p with
@@ -310,12 +947,7 @@ Module Make (Import W0:CyclicType) <: NType.
(Zpos p + n - 1); auto with zarith.
intros a3 b3 H12 H13; apply H4; auto with zarith.
apply Zlt_le_trans with (1 := H12).
- case (Zle_or_lt 1 n); intros HH.
- apply Zpower_le_monotone; auto with zarith.
- apply Zle_trans with 0; auto with zarith.
- assert (HH1: n - 1 < 0); auto with zarith.
- generalize HH1; case (n - 1); auto with zarith.
- intros p1 HH2; discriminate.
+ apply Zpower_le_monotone2; auto with zarith.
intros n a b cont H H2 H3.
simpl gcd_gt_aux.
apply Zspec_gcd_gt_body with (n + 1); auto with zarith.
@@ -345,7 +977,7 @@ Module Make (Import W0:CyclicType) <: NType.
intros; apply False_ind; auto with zarith.
Qed.
- Definition gcd a b :=
+ Definition gcd (a b : t) : t :=
match compare a b with
| Eq => a
| Lt => gcd_gt b a
@@ -357,7 +989,7 @@ Module Make (Import W0:CyclicType) <: NType.
intros a b.
case (spec_digits a); intros H1 H2.
case (spec_digits b); intros H3 H4.
- unfold gcd; generalize (spec_compare_aux a b); case compare.
+ unfold gcd. rewrite spec_compare. case Zcompare_spec.
intros HH; rewrite HH; apply sym_equal; apply Zis_gcd_gcd; auto.
apply Zis_gcd_refl.
intros; apply trans_equal with (Zgcd [b] [a]).
@@ -365,13 +997,91 @@ Module Make (Import W0:CyclicType) <: NType.
apply Zis_gcd_gcd; auto with zarith.
apply Zgcd_is_pos.
apply Zis_gcd_sym; apply Zgcd_is_gcd.
- intros; apply spec_gcd_gt; auto.
+ intros; apply spec_gcd_gt; auto with zarith.
+ Qed.
+
+ (** * Parity test *)
+
+ Definition even : t -> bool := Eval red_t in
+ iter_t (fun n x => ZnZ.is_even x).
+
+ Definition odd x := negb (even x).
+
+ Lemma even_fold : even = iter_t (fun n x => ZnZ.is_even x).
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_even_aux: forall x,
+ if even x then [x] mod 2 = 0 else [x] mod 2 = 1.
+ Proof.
+ intros x. rewrite even_fold. destr_t x as (n,x).
+ exact (ZnZ.spec_is_even x).
+ Qed.
+
+ Theorem spec_even: forall x, even x = Zeven_bool [x].
+ Proof.
+ intros x. assert (H := spec_even_aux x). symmetry.
+ rewrite (Z_div_mod_eq_full [x] 2); auto with zarith.
+ destruct (even x); rewrite H, ?Zplus_0_r.
+ rewrite Zeven_bool_iff. apply Zeven_2p.
+ apply not_true_is_false. rewrite Zeven_bool_iff.
+ apply Zodd_not_Zeven. apply Zodd_2p_plus_1.
Qed.
+ Theorem spec_odd: forall x, odd x = Zodd_bool [x].
+ Proof.
+ intros x. unfold odd.
+ assert (H := spec_even_aux x). symmetry.
+ rewrite (Z_div_mod_eq_full [x] 2); auto with zarith.
+ destruct (even x); rewrite H, ?Zplus_0_r; simpl negb.
+ apply not_true_is_false. rewrite Zodd_bool_iff.
+ apply Zeven_not_Zodd. apply Zeven_2p.
+ apply Zodd_bool_iff. apply Zodd_2p_plus_1.
+ Qed.
(** * Conversion *)
- Definition of_N x :=
+ Definition pheight p :=
+ Peano.pred (nat_of_P (get_height (ZnZ.digits (dom_op 0)) (plength p))).
+
+ Theorem pheight_correct: forall p,
+ Zpos p < 2 ^ (Zpos (ZnZ.digits (dom_op 0)) * 2 ^ (Z_of_nat (pheight p))).
+ Proof.
+ intros p; unfold pheight.
+ assert (F1: forall x, Z_of_nat (Peano.pred (nat_of_P x)) = Zpos x - 1).
+ intros x.
+ assert (Zsucc (Z_of_nat (Peano.pred (nat_of_P x))) = Zpos x); auto with zarith.
+ rewrite <- inj_S.
+ rewrite <- (fun x => S_pred x 0); auto with zarith.
+ rewrite Zpos_eq_Z_of_nat_o_nat_of_P; auto.
+ apply lt_le_trans with 1%nat; auto with zarith.
+ exact (le_Pmult_nat x 1).
+ rewrite F1; clear F1.
+ assert (F2:= (get_height_correct (ZnZ.digits (dom_op 0)) (plength p))).
+ apply Zlt_le_trans with (Zpos (Psucc p)).
+ rewrite Zpos_succ_morphism; auto with zarith.
+ apply Zle_trans with (1 := plength_pred_correct (Psucc p)).
+ rewrite Ppred_succ.
+ apply Zpower_le_monotone2; auto with zarith.
+ Qed.
+
+ Definition of_pos (x:positive) : t :=
+ let n := pheight x in
+ reduce n (snd (ZnZ.of_pos x)).
+
+ Theorem spec_of_pos: forall x,
+ [of_pos x] = Zpos x.
+ Proof.
+ intros x; unfold of_pos.
+ rewrite spec_reduce.
+ simpl.
+ apply ZnZ.of_pos_correct.
+ unfold base.
+ apply Zlt_le_trans with (1 := pheight_correct x).
+ apply Zpower_le_monotone2; auto with zarith.
+ rewrite (digits_dom_op (_ _)), Pshiftl_nat_Zpower. auto with zarith.
+ Qed.
+
+ Definition of_N (x:N) : t :=
match x with
| BinNat.N0 => zero
| Npos p => of_pos p
@@ -381,51 +1091,437 @@ Module Make (Import W0:CyclicType) <: NType.
[of_N x] = Z_of_N x.
Proof.
intros x; case x.
- simpl of_N.
- unfold zero, w_0, to_Z; rewrite (spec_0 w0_spec); auto.
+ simpl of_N. exact spec_0.
intros p; exact (spec_of_pos p).
Qed.
+ (** * [head0] and [tail0]
- (** * Shift *)
+ Number of zero at the beginning and at the end of
+ the representation of the number.
+ NB: these functions are not morphism for setoid [eq].
+ *)
- Definition shiftr n x :=
- match compare n (Ndigits x) with
- | Lt => unsafe_shiftr n x
- | _ => N0 w_0
- end.
+ Local Notation head0n := (fun n =>
+ let head0 := ZnZ.head0 in
+ fun x => reduce n (head0 x)).
+
+ Definition head0 : t -> t := Eval red_t in iter_t head0n.
+
+ Lemma head0_fold : head0 = iter_t head0n.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_head00: forall x, [x] = 0 -> [head0 x] = Zpos (digits x).
+ Proof.
+ intros x. rewrite head0_fold, digits_fold. destr_t x as (n,x).
+ exact (ZnZ.spec_head00 x).
+ Qed.
+
+ Lemma pow2_pos_minus_1 : forall z, 0<z -> 2^(z-1) = 2^z / 2.
+ Proof.
+ intros. apply Zdiv_unique with 0; auto with zarith.
+ change 2 with (2^1) at 2.
+ rewrite <- Zpower_exp; auto with zarith.
+ rewrite Zplus_0_r. f_equal. auto with zarith.
+ Qed.
- Theorem spec_shiftr: forall n x,
- [shiftr n x] = [x] / 2 ^ [n].
- Proof.
- intros n x; unfold shiftr;
- generalize (spec_compare_aux n (Ndigits x)); case compare; intros H.
- apply trans_equal with (1 := spec_0 w0_spec).
- apply sym_equal; apply Zdiv_small; rewrite H.
- rewrite spec_Ndigits; exact (spec_digits x).
- rewrite <- spec_unsafe_shiftr; auto with zarith.
- apply trans_equal with (1 := spec_0 w0_spec).
- apply sym_equal; apply Zdiv_small.
- rewrite spec_Ndigits in H; case (spec_digits x); intros H1 H2.
- split; auto.
- apply Zlt_le_trans with (1 := H2).
- apply Zpower_le_monotone; auto with zarith.
- Qed.
-
- Definition shiftl_aux_body cont n x :=
- match compare n (head0 x) with
- Gt => cont n (double_size x)
- | _ => unsafe_shiftl n x
+ Theorem spec_head0: forall x, 0 < [x] ->
+ 2 ^ (Zpos (digits x) - 1) <= 2 ^ [head0 x] * [x] < 2 ^ Zpos (digits x).
+ Proof.
+ intros x. rewrite pow2_pos_minus_1 by (red; auto).
+ rewrite head0_fold, digits_fold. destr_t x as (n,x). exact (ZnZ.spec_head0 x).
+ Qed.
+
+ Local Notation tail0n := (fun n =>
+ let tail0 := ZnZ.tail0 in
+ fun x => reduce n (tail0 x)).
+
+ Definition tail0 : t -> t := Eval red_t in iter_t tail0n.
+
+ Lemma tail0_fold : tail0 = iter_t tail0n.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_tail00: forall x, [x] = 0 -> [tail0 x] = Zpos (digits x).
+ Proof.
+ intros x. rewrite tail0_fold, digits_fold. destr_t x as (n,x).
+ exact (ZnZ.spec_tail00 x).
+ Qed.
+
+ Theorem spec_tail0: forall x,
+ 0 < [x] -> exists y, 0 <= y /\ [x] = (2 * y + 1) * 2 ^ [tail0 x].
+ Proof.
+ intros x. rewrite tail0_fold. destr_t x as (n,x). exact (ZnZ.spec_tail0 x).
+ Qed.
+
+ (** * [Ndigits]
+
+ Same as [digits] but encoded using large integers
+ NB: this function is not a morphism for setoid [eq].
+ *)
+
+ Local Notation Ndigitsn := (fun n =>
+ let d := reduce n (ZnZ.zdigits (dom_op n)) in
+ fun _ => d).
+
+ Definition Ndigits : t -> t := Eval red_t in iter_t Ndigitsn.
+
+ Lemma Ndigits_fold : Ndigits = iter_t Ndigitsn.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_Ndigits: forall x, [Ndigits x] = Zpos (digits x).
+ Proof.
+ intros x. rewrite Ndigits_fold, digits_fold. destr_t x as (n,x).
+ apply ZnZ.spec_zdigits.
+ Qed.
+
+ (** * Binary logarithm *)
+
+ Local Notation log2n := (fun n =>
+ let op := dom_op n in
+ let zdigits := ZnZ.zdigits op in
+ let head0 := ZnZ.head0 in
+ let sub_carry := ZnZ.sub_carry in
+ fun x => reduce n (sub_carry zdigits (head0 x))).
+
+ Definition log2 : t -> t := Eval red_t in
+ let log2 := iter_t log2n in
+ fun x => if eqb x zero then zero else log2 x.
+
+ Lemma log2_fold :
+ log2 = fun x => if eqb x zero then zero else iter_t log2n x.
+ Proof. red_t; reflexivity. Qed.
+
+ Lemma spec_log2_0 : forall x, [x] = 0 -> [log2 x] = 0.
+ Proof.
+ intros x H. rewrite log2_fold.
+ rewrite spec_eqb, H. rewrite spec_0. simpl. exact spec_0.
+ Qed.
+
+ Lemma head0_zdigits : forall n (x : dom_t n),
+ 0 < ZnZ.to_Z x ->
+ ZnZ.to_Z (ZnZ.head0 x) < ZnZ.to_Z (ZnZ.zdigits (dom_op n)).
+ Proof.
+ intros n x H.
+ destruct (ZnZ.spec_head0 x H) as (_,H0).
+ intros.
+ assert (H1 := ZnZ.spec_to_Z (ZnZ.head0 x)).
+ assert (H2 := ZnZ.spec_to_Z (ZnZ.zdigits (dom_op n))).
+ unfold base in *.
+ rewrite ZnZ.spec_zdigits in H2 |- *.
+ set (h := ZnZ.to_Z (ZnZ.head0 x)) in *; clearbody h.
+ set (d := ZnZ.digits (dom_op n)) in *; clearbody d.
+ destruct (Z_lt_le_dec h (Zpos d)); auto. exfalso.
+ assert (1 * 2^Zpos d <= ZnZ.to_Z x * 2^h).
+ apply Zmult_le_compat; auto with zarith.
+ apply Zpower_le_monotone2; auto with zarith.
+ rewrite Zmult_comm in H0. auto with zarith.
+ Qed.
+
+ Lemma spec_log2_pos : forall x, [x]<>0 ->
+ 2^[log2 x] <= [x] < 2^([log2 x]+1).
+ Proof.
+ intros x H. rewrite log2_fold.
+ rewrite spec_eqb. rewrite spec_0.
+ case Z.eqb_spec.
+ auto with zarith.
+ clear H.
+ destr_t x as (n,x). intros H.
+ rewrite ZnZ.spec_sub_carry.
+ assert (H0 := ZnZ.spec_to_Z x).
+ assert (H1 := ZnZ.spec_to_Z (ZnZ.head0 x)).
+ assert (H2 := ZnZ.spec_to_Z (ZnZ.zdigits (dom_op n))).
+ assert (H3 := head0_zdigits n x).
+ rewrite Zmod_small by auto with zarith.
+ rewrite (Z.mul_lt_mono_pos_l (2^(ZnZ.to_Z (ZnZ.head0 x))));
+ auto with zarith.
+ rewrite (Z.mul_le_mono_pos_l _ _ (2^(ZnZ.to_Z (ZnZ.head0 x))));
+ auto with zarith.
+ rewrite <- 2 Zpower_exp; auto with zarith.
+ rewrite Z.add_sub_assoc, Zplus_minus.
+ rewrite Z.sub_simpl_r, Zplus_minus.
+ rewrite ZnZ.spec_zdigits.
+ rewrite pow2_pos_minus_1 by (red; auto).
+ apply ZnZ.spec_head0; auto with zarith.
+ Qed.
+
+ Lemma spec_log2 : forall x, [log2 x] = Z.log2 [x].
+ Proof.
+ intros. destruct (Z_lt_ge_dec 0 [x]).
+ symmetry. apply Z.log2_unique. apply spec_pos.
+ apply spec_log2_pos. intro EQ; rewrite EQ in *; auto with zarith.
+ rewrite spec_log2_0. rewrite Z.log2_nonpos; auto with zarith.
+ generalize (spec_pos x); auto with zarith.
+ Qed.
+
+ Lemma log2_digits_head0 : forall x, 0 < [x] ->
+ [log2 x] = Zpos (digits x) - [head0 x] - 1.
+ Proof.
+ intros. rewrite log2_fold.
+ rewrite spec_eqb. rewrite spec_0.
+ case Z.eqb_spec.
+ auto with zarith.
+ intros _. revert H. rewrite digits_fold, head0_fold. destr_t x as (n,x).
+ rewrite ZnZ.spec_sub_carry.
+ intros.
+ generalize (head0_zdigits n x H).
+ generalize (ZnZ.spec_to_Z (ZnZ.head0 x)).
+ generalize (ZnZ.spec_to_Z (ZnZ.zdigits (dom_op n))).
+ rewrite ZnZ.spec_zdigits. intros. apply Zmod_small.
+ auto with zarith.
+ Qed.
+
+ (** * Right shift *)
+
+ Local Notation shiftrn := (fun n =>
+ let op := dom_op n in
+ let zdigits := ZnZ.zdigits op in
+ let sub_c := ZnZ.sub_c in
+ let add_mul_div := ZnZ.add_mul_div in
+ let zzero := ZnZ.zero in
+ fun x p => match sub_c zdigits p with
+ | C0 d => reduce n (add_mul_div d zzero x)
+ | C1 _ => zero
+ end).
+
+ Definition shiftr : t -> t -> t := Eval red_t in
+ same_level shiftrn.
+
+ Lemma shiftr_fold : shiftr = same_level shiftrn.
+ Proof. red_t; reflexivity. Qed.
+
+ Lemma div_pow2_bound :forall x y z,
+ 0 <= x -> 0 <= y -> x < z -> 0 <= x / 2 ^ y < z.
+ Proof.
+ intros x y z HH HH1 HH2.
+ split; auto with zarith.
+ apply Zle_lt_trans with (2 := HH2); auto with zarith.
+ apply Zdiv_le_upper_bound; auto with zarith.
+ pattern x at 1; replace x with (x * 2 ^ 0); auto with zarith.
+ apply Zmult_le_compat_l; auto.
+ apply Zpower_le_monotone2; auto with zarith.
+ rewrite Zpower_0_r; ring.
+ Qed.
+
+ Theorem spec_shiftr_pow2 : forall x n,
+ [shiftr x n] = [x] / 2 ^ [n].
+ Proof.
+ intros x y. rewrite shiftr_fold. apply spec_same_level. clear x y.
+ intros n x p. simpl.
+ assert (Hx := ZnZ.spec_to_Z x).
+ assert (Hy := ZnZ.spec_to_Z p).
+ generalize (ZnZ.spec_sub_c (ZnZ.zdigits (dom_op n)) p).
+ case ZnZ.sub_c; intros d H; unfold interp_carry in *; simpl.
+ (** Subtraction without underflow : [ p <= digits ] *)
+ rewrite spec_reduce.
+ rewrite ZnZ.spec_zdigits in H.
+ rewrite ZnZ.spec_add_mul_div by auto with zarith.
+ rewrite ZnZ.spec_0, Zmult_0_l, Zplus_0_l.
+ rewrite Zmod_small.
+ f_equal. f_equal. auto with zarith.
+ split. auto with zarith.
+ apply div_pow2_bound; auto with zarith.
+ (** Subtraction with underflow : [ digits < p ] *)
+ rewrite ZnZ.spec_0. symmetry.
+ apply Zdiv_small.
+ split; auto with zarith.
+ apply Zlt_le_trans with (base (ZnZ.digits (dom_op n))); auto with zarith.
+ unfold base. apply Zpower_le_monotone2; auto with zarith.
+ rewrite ZnZ.spec_zdigits in H.
+ generalize (ZnZ.spec_to_Z d); auto with zarith.
+ Qed.
+
+ Lemma spec_shiftr: forall x p, [shiftr x p] = Z.shiftr [x] [p].
+ Proof.
+ intros.
+ now rewrite spec_shiftr_pow2, Z.shiftr_div_pow2 by apply spec_pos.
+ Qed.
+
+ (** * Left shift *)
+
+ (** First an unsafe version, working correctly only if
+ the representation is large enough *)
+
+ Local Notation unsafe_shiftln := (fun n =>
+ let op := dom_op n in
+ let add_mul_div := ZnZ.add_mul_div in
+ let zero := ZnZ.zero in
+ fun x p => reduce n (add_mul_div p x zero)).
+
+ Definition unsafe_shiftl : t -> t -> t := Eval red_t in
+ same_level unsafe_shiftln.
+
+ Lemma unsafe_shiftl_fold : unsafe_shiftl = same_level unsafe_shiftln.
+ Proof. red_t; reflexivity. Qed.
+
+ Theorem spec_unsafe_shiftl_aux : forall x p K,
+ 0 <= K ->
+ [x] < 2^K ->
+ [p] + K <= Zpos (digits x) ->
+ [unsafe_shiftl x p] = [x] * 2 ^ [p].
+ Proof.
+ intros x p.
+ rewrite unsafe_shiftl_fold. rewrite digits_level.
+ apply spec_same_level_dep.
+ intros n m z z' r LE H K HK H1 H2. apply (H K); auto.
+ transitivity (Zpos (ZnZ.digits (dom_op n))); auto.
+ apply digits_dom_op_incr; auto.
+ clear x p.
+ intros n x p K HK Hx Hp. simpl. rewrite spec_reduce.
+ destruct (ZnZ.spec_to_Z x).
+ destruct (ZnZ.spec_to_Z p).
+ rewrite ZnZ.spec_add_mul_div by (omega with *).
+ rewrite ZnZ.spec_0, Zdiv_0_l, Zplus_0_r.
+ apply Zmod_small. unfold base.
+ split; auto with zarith.
+ rewrite Zmult_comm.
+ apply Zlt_le_trans with (2^(ZnZ.to_Z p + K)).
+ rewrite Zpower_exp; auto with zarith.
+ apply Zmult_lt_compat_l; auto with zarith.
+ apply Zpower_le_monotone2; auto with zarith.
+ Qed.
+
+ Theorem spec_unsafe_shiftl: forall x p,
+ [p] <= [head0 x] -> [unsafe_shiftl x p] = [x] * 2 ^ [p].
+ Proof.
+ intros.
+ destruct (Z_eq_dec [x] 0) as [EQ|NEQ].
+ (* [x] = 0 *)
+ apply spec_unsafe_shiftl_aux with 0; auto with zarith.
+ now rewrite EQ.
+ rewrite spec_head00 in *; auto with zarith.
+ (* [x] <> 0 *)
+ apply spec_unsafe_shiftl_aux with ([log2 x] + 1); auto with zarith.
+ generalize (spec_pos (log2 x)); auto with zarith.
+ destruct (spec_log2_pos x); auto with zarith.
+ rewrite log2_digits_head0; auto with zarith.
+ generalize (spec_pos x); auto with zarith.
+ Qed.
+
+ (** Then we define a function doubling the size of the representation
+ but without changing the value of the number. *)
+
+ Local Notation double_size_n := (fun n =>
+ let zero := ZnZ.zero in
+ fun x => mk_t_S n (WW zero x)).
+
+ Definition double_size : t -> t := Eval red_t in
+ iter_t double_size_n.
+
+ Lemma double_size_fold : double_size = iter_t double_size_n.
+ Proof. red_t; reflexivity. Qed.
+
+ Lemma double_size_level : forall x, level (double_size x) = S (level x).
+ Proof.
+ intros x. rewrite double_size_fold; unfold level at 2. destr_t x as (n,x).
+ apply mk_t_S_level.
+ Qed.
+
+ Theorem spec_double_size_digits:
+ forall x, Zpos (digits (double_size x)) = 2 * (Zpos (digits x)).
+ Proof.
+ intros x. rewrite ! digits_level, double_size_level.
+ rewrite 2 digits_dom_op, 2 Pshiftl_nat_Zpower,
+ inj_S, Zpower_Zsucc; auto with zarith.
+ ring.
+ Qed.
+
+ Theorem spec_double_size: forall x, [double_size x] = [x].
+ Proof.
+ intros x. rewrite double_size_fold. destr_t x as (n,x).
+ rewrite spec_mk_t_S. simpl. rewrite ZnZ.spec_0. auto with zarith.
+ Qed.
+
+ Theorem spec_double_size_head0:
+ forall x, 2 * [head0 x] <= [head0 (double_size x)].
+ Proof.
+ intros x.
+ assert (F1:= spec_pos (head0 x)).
+ assert (F2: 0 < Zpos (digits x)).
+ red; auto.
+ case (Zle_lt_or_eq _ _ (spec_pos x)); intros HH.
+ generalize HH; rewrite <- (spec_double_size x); intros HH1.
+ case (spec_head0 x HH); intros _ HH2.
+ case (spec_head0 _ HH1).
+ rewrite (spec_double_size x); rewrite (spec_double_size_digits x).
+ intros HH3 _.
+ case (Zle_or_lt ([head0 (double_size x)]) (2 * [head0 x])); auto; intros HH4.
+ absurd (2 ^ (2 * [head0 x] )* [x] < 2 ^ [head0 (double_size x)] * [x]); auto.
+ apply Zle_not_lt.
+ apply Zmult_le_compat_r; auto with zarith.
+ apply Zpower_le_monotone2; auto; auto with zarith.
+ assert (HH5: 2 ^[head0 x] <= 2 ^(Zpos (digits x) - 1)).
+ case (Zle_lt_or_eq 1 [x]); auto with zarith; intros HH5.
+ apply Zmult_le_reg_r with (2 ^ 1); auto with zarith.
+ rewrite <- (fun x y z => Zpower_exp x (y - z)); auto with zarith.
+ assert (tmp: forall x, x - 1 + 1 = x); [intros; ring | rewrite tmp; clear tmp].
+ apply Zle_trans with (2 := Zlt_le_weak _ _ HH2).
+ apply Zmult_le_compat_l; auto with zarith.
+ rewrite Zpower_1_r; auto with zarith.
+ apply Zpower_le_monotone2; auto with zarith.
+ case (Zle_or_lt (Zpos (digits x)) [head0 x]); auto with zarith; intros HH6.
+ absurd (2 ^ Zpos (digits x) <= 2 ^ [head0 x] * [x]); auto with zarith.
+ rewrite <- HH5; rewrite Zmult_1_r.
+ apply Zpower_le_monotone2; auto with zarith.
+ rewrite (Zmult_comm 2).
+ rewrite Zpower_mult; auto with zarith.
+ rewrite Zpower_2.
+ apply Zlt_le_trans with (2 := HH3).
+ rewrite <- Zmult_assoc.
+ replace (2 * Zpos (digits x) - 1) with
+ ((Zpos (digits x) - 1) + (Zpos (digits x))).
+ rewrite Zpower_exp; auto with zarith.
+ apply Zmult_lt_compat2; auto with zarith.
+ split; auto with zarith.
+ apply Zmult_lt_0_compat; auto with zarith.
+ rewrite Zpos_xO; ring.
+ apply Zlt_le_weak; auto.
+ repeat rewrite spec_head00; auto.
+ rewrite spec_double_size_digits.
+ rewrite Zpos_xO; auto with zarith.
+ rewrite spec_double_size; auto.
+ Qed.
+
+ Theorem spec_double_size_head0_pos:
+ forall x, 0 < [head0 (double_size x)].
+ Proof.
+ intros x.
+ assert (F: 0 < Zpos (digits x)).
+ red; auto.
+ case (Zle_lt_or_eq _ _ (spec_pos (head0 (double_size x)))); auto; intros F0.
+ case (Zle_lt_or_eq _ _ (spec_pos (head0 x))); intros F1.
+ apply Zlt_le_trans with (2 := (spec_double_size_head0 x)); auto with zarith.
+ case (Zle_lt_or_eq _ _ (spec_pos x)); intros F3.
+ generalize F3; rewrite <- (spec_double_size x); intros F4.
+ absurd (2 ^ (Zpos (xO (digits x)) - 1) < 2 ^ (Zpos (digits x))).
+ apply Zle_not_lt.
+ apply Zpower_le_monotone2; auto with zarith.
+ rewrite Zpos_xO; auto with zarith.
+ case (spec_head0 x F3).
+ rewrite <- F1; rewrite Zpower_0_r; rewrite Zmult_1_l; intros _ HH.
+ apply Zle_lt_trans with (2 := HH).
+ case (spec_head0 _ F4).
+ rewrite (spec_double_size x); rewrite (spec_double_size_digits x).
+ rewrite <- F0; rewrite Zpower_0_r; rewrite Zmult_1_l; auto.
+ generalize F1; rewrite (spec_head00 _ (sym_equal F3)); auto with zarith.
+ Qed.
+
+ (** Finally we iterate [double_size] enough before [unsafe_shiftl]
+ in order to get a fully correct [shiftl]. *)
+
+ Definition shiftl_aux_body cont x n :=
+ match compare n (head0 x) with
+ Gt => cont (double_size x) n
+ | _ => unsafe_shiftl x n
end.
- Theorem spec_shiftl_aux_body: forall n p x cont,
+ Theorem spec_shiftl_aux_body: forall n x p cont,
2^ Zpos p <= [head0 x] ->
(forall x, 2 ^ (Zpos p + 1) <= [head0 x]->
- [cont n x] = [x] * 2 ^ [n]) ->
- [shiftl_aux_body cont n x] = [x] * 2 ^ [n].
+ [cont x n] = [x] * 2 ^ [n]) ->
+ [shiftl_aux_body cont x n] = [x] * 2 ^ [n].
Proof.
- intros n p x cont H1 H2; unfold shiftl_aux_body.
- generalize (spec_compare_aux n (head0 x)); case compare; intros H.
+ intros n x p cont H1 H2; unfold shiftl_aux_body.
+ rewrite spec_compare; case Zcompare_spec; intros H.
apply spec_unsafe_shiftl; auto with zarith.
apply spec_unsafe_shiftl; auto with zarith.
rewrite H2.
@@ -435,22 +1531,22 @@ Module Make (Import W0:CyclicType) <: NType.
rewrite Zpower_1_r; apply Zmult_le_compat_l; auto with zarith.
Qed.
- Fixpoint shiftl_aux p cont n x {struct p} :=
+ Fixpoint shiftl_aux p cont x n :=
shiftl_aux_body
- (fun n x => match p with
- | xH => cont n x
- | xO p => shiftl_aux p (shiftl_aux p cont) n x
- | xI p => shiftl_aux p (shiftl_aux p cont) n x
- end) n x.
+ (fun x n => match p with
+ | xH => cont x n
+ | xO p => shiftl_aux p (shiftl_aux p cont) x n
+ | xI p => shiftl_aux p (shiftl_aux p cont) x n
+ end) x n.
- Theorem spec_shiftl_aux: forall p q n x cont,
+ Theorem spec_shiftl_aux: forall p q x n cont,
2 ^ (Zpos q) <= [head0 x] ->
(forall x, 2 ^ (Zpos p + Zpos q) <= [head0 x] ->
- [cont n x] = [x] * 2 ^ [n]) ->
- [shiftl_aux p cont n x] = [x] * 2 ^ [n].
+ [cont x n] = [x] * 2 ^ [n]) ->
+ [shiftl_aux p cont x n] = [x] * 2 ^ [n].
Proof.
intros p; elim p; unfold shiftl_aux; fold shiftl_aux; clear p.
- intros p Hrec q n x cont H1 H2.
+ intros p Hrec q x n cont H1 H2.
apply spec_shiftl_aux_body with (q); auto.
intros x1 H3; apply Hrec with (q + 1)%positive; auto.
intros x2 H4; apply Hrec with (p + q + 1)%positive; auto.
@@ -465,7 +1561,7 @@ Module Make (Import W0:CyclicType) <: NType.
apply spec_shiftl_aux_body with (q); auto.
intros x1 H3; apply Hrec with (q); auto.
apply Zle_trans with (2 := H3); auto with zarith.
- apply Zpower_le_monotone; auto with zarith.
+ apply Zpower_le_monotone2; auto with zarith.
intros x2 H4; apply Hrec with (p + q)%positive; auto.
intros x3 H5; apply H2.
rewrite (Zpos_xO p).
@@ -477,20 +1573,20 @@ Module Make (Import W0:CyclicType) <: NType.
rewrite Zplus_comm; auto.
Qed.
- Definition shiftl n x :=
+ Definition shiftl x n :=
shiftl_aux_body
(shiftl_aux_body
- (shiftl_aux (digits n) unsafe_shiftl)) n x.
+ (shiftl_aux (digits n) unsafe_shiftl)) x n.
- Theorem spec_shiftl: forall n x,
- [shiftl n x] = [x] * 2 ^ [n].
+ Theorem spec_shiftl_pow2 : forall x n,
+ [shiftl x n] = [x] * 2 ^ [n].
Proof.
- intros n x; unfold shiftl, shiftl_aux_body.
- generalize (spec_compare_aux n (head0 x)); case compare; intros H.
+ intros x n; unfold shiftl, shiftl_aux_body.
+ rewrite spec_compare; case Zcompare_spec; intros H.
apply spec_unsafe_shiftl; auto with zarith.
apply spec_unsafe_shiftl; auto with zarith.
rewrite <- (spec_double_size x).
- generalize (spec_compare_aux n (head0 (double_size x))); case compare; intros H1.
+ rewrite spec_compare; case Zcompare_spec; intros H1.
apply spec_unsafe_shiftl; auto with zarith.
apply spec_unsafe_shiftl; auto with zarith.
rewrite <- (spec_double_size (double_size x)).
@@ -504,21 +1600,67 @@ Module Make (Import W0:CyclicType) <: NType.
apply Zle_trans with (2 := H2).
apply Zle_trans with (2 ^ Zpos (digits n)); auto with zarith.
case (spec_digits n); auto with zarith.
- apply Zpower_le_monotone; auto with zarith.
+ apply Zpower_le_monotone2; auto with zarith.
Qed.
+ Lemma spec_shiftl: forall x p, [shiftl x p] = Z.shiftl [x] [p].
+ Proof.
+ intros.
+ now rewrite spec_shiftl_pow2, Z.shiftl_mul_pow2 by apply spec_pos.
+ Qed.
- (** * Zero and One *)
+ (** Other bitwise operations *)
- Theorem spec_0: [zero] = 0.
+ Definition testbit x n := odd (shiftr x n).
+
+ Lemma spec_testbit: forall x p, testbit x p = Z.testbit [x] [p].
Proof.
- exact (spec_0 w0_spec).
+ intros. unfold testbit. symmetry.
+ rewrite spec_odd, spec_shiftr. apply Z.testbit_odd.
Qed.
- Theorem spec_1: [one] = 1.
+ Definition div2 x := shiftr x one.
+
+ Lemma spec_div2: forall x, [div2 x] = Z.div2 [x].
Proof.
- exact (spec_1 w0_spec).
+ intros. unfold div2. symmetry.
+ rewrite spec_shiftr, spec_1. apply Z.div2_spec.
Qed.
+ (** TODO : provide efficient versions instead of just converting
+ from/to N (see with Laurent) *)
+
+ Definition lor x y := of_N (N.lor (to_N x) (to_N y)).
+ Definition land x y := of_N (N.land (to_N x) (to_N y)).
+ Definition ldiff x y := of_N (N.ldiff (to_N x) (to_N y)).
+ Definition lxor x y := of_N (N.lxor (to_N x) (to_N y)).
+
+ Lemma spec_land: forall x y, [land x y] = Z.land [x] [y].
+ Proof.
+ intros x y. unfold land. rewrite spec_of_N. unfold to_N.
+ generalize (spec_pos x), (spec_pos y).
+ destruct [x], [y]; trivial; (now destruct 1) || (now destruct 2).
+ Qed.
+
+ Lemma spec_lor: forall x y, [lor x y] = Z.lor [x] [y].
+ Proof.
+ intros x y. unfold lor. rewrite spec_of_N. unfold to_N.
+ generalize (spec_pos x), (spec_pos y).
+ destruct [x], [y]; trivial; (now destruct 1) || (now destruct 2).
+ Qed.
+
+ Lemma spec_ldiff: forall x y, [ldiff x y] = Z.ldiff [x] [y].
+ Proof.
+ intros x y. unfold ldiff. rewrite spec_of_N. unfold to_N.
+ generalize (spec_pos x), (spec_pos y).
+ destruct [x], [y]; trivial; (now destruct 1) || (now destruct 2).
+ Qed.
+
+ Lemma spec_lxor: forall x y, [lxor x y] = Z.lxor [x] [y].
+ Proof.
+ intros x y. unfold lxor. rewrite spec_of_N. unfold to_N.
+ generalize (spec_pos x), (spec_pos y).
+ destruct [x], [y]; trivial; (now destruct 1) || (now destruct 2).
+ Qed.
End Make.
diff --git a/theories/Numbers/Natural/BigN/NMake_gen.ml b/theories/Numbers/Natural/BigN/NMake_gen.ml
index 67a62c40..59d440c3 100644
--- a/theories/Numbers/Natural/BigN/NMake_gen.ml
+++ b/theories/Numbers/Natural/BigN/NMake_gen.ml
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,100 +8,88 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NMake_gen.ml 14641 2011-11-06 11:59:10Z herbelin $ i*)
+(*S NMake_gen.ml : this file generates NMake_gen.v *)
-(*S NMake_gen.ml : this file generates NMake.v *)
-
-(*s The two parameters that control the generation: *)
+(*s The parameter that control the generation: *)
let size = 6 (* how many times should we repeat the Z/nZ --> Z/2nZ
process before relying on a generic construct *)
-let gen_proof = true (* should we generate proofs ? *)
-
(*s Some utilities *)
-let t = "t"
-let c = "N"
-let pz n = if n == 0 then "w_0" else "W0"
-let rec gen2 n = if n == 0 then "1" else if n == 1 then "2"
- else "2 * " ^ (gen2 (n - 1))
-let rec genxO n s =
- if n == 0 then s else " (xO" ^ (genxO (n - 1) s) ^ ")"
+let rec iter_str n s = if n = 0 then "" else (iter_str (n-1) s) ^ s
-(* NB: in ocaml >= 3.10, we could use Printf.ifprintf for printing to
- /dev/null, but for being compatible with earlier ocaml and not
- relying on system-dependent stuff like open_out "/dev/null",
- let's use instead a magical hack *)
+let rec iter_str_gen n f = if n < 0 then "" else (iter_str_gen (n-1) f) ^ (f n)
-(* Standard printer, with a final newline *)
-let pr s = Printf.printf (s^^"\n")
-(* Printing to /dev/null *)
-let pn = (fun s -> Obj.magic (fun _ _ _ _ _ _ _ _ _ _ _ _ _ _ -> ())
- : ('a, out_channel, unit) format -> 'a)
-(* Proof printer : prints iff gen_proof is true *)
-let pp = if gen_proof then pr else pn
-(* Printer for admitted parts : prints iff gen_proof is false *)
-let pa = if not gen_proof then pr else pn
-(* Same as before, but without the final newline *)
-let pr0 = Printf.printf
-let pp0 = if gen_proof then pr0 else pn
+let rec iter_name i j base sep =
+ if i >= j then base^(string_of_int i)
+ else (iter_name i (j-1) base sep)^sep^" "^base^(string_of_int j)
+let pr s = Printf.printf (s^^"\n")
(*s The actual printing *)
let _ =
- pr "(************************************************************************)";
- pr "(* v * The Coq Proof Assistant / The Coq Development Team *)";
- pr "(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)";
- pr "(* \\VV/ **************************************************************)";
- pr "(* // * This file is distributed under the terms of the *)";
- pr "(* * GNU Lesser General Public License Version 2.1 *)";
- pr "(************************************************************************)";
- pr "(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)";
- pr "(************************************************************************)";
- pr "";
- pr "(** * NMake *)";
- pr "";
- pr "(** From a cyclic Z/nZ representation to arbitrary precision natural numbers.*)";
- pr "";
- pr "(** Remark: File automatically generated by NMake_gen.ml, DO NOT EDIT ! *)";
- pr "";
- pr "Require Import BigNumPrelude ZArith CyclicAxioms";
- pr " DoubleType DoubleMul DoubleDivn1 DoubleCyclic Nbasic";
- pr " Wf_nat StreamMemo.";
- pr "";
- pr "Module Make (Import W0:CyclicType).";
- pr "";
+pr
+"(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
+(* \\VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
+(************************************************************************)
- pr " Definition w0 := W0.w.";
- for i = 1 to size do
- pr " Definition w%i := zn2z w%i." i (i-1)
- done;
- pr "";
+(** * NMake_gen *)
- pr " Definition w0_op := W0.w_op.";
- for i = 1 to 3 do
- pr " Definition w%i_op := mk_zn2z_op w%i_op." i (i-1)
- done;
- for i = 4 to size + 3 do
- pr " Definition w%i_op := mk_zn2z_op_karatsuba w%i_op." i (i-1)
- done;
- pr "";
+(** From a cyclic Z/nZ representation to arbitrary precision natural numbers.*)
+
+(** Remark: File automatically generated by NMake_gen.ml, DO NOT EDIT ! *)
+
+Require Import BigNumPrelude ZArith Ndigits CyclicAxioms
+ DoubleType DoubleMul DoubleDivn1 DoubleCyclic Nbasic
+ Wf_nat StreamMemo.
+
+Module Make (W0:CyclicType) <: NAbstract.
+
+ (** * The word types *)
+";
+
+pr " Local Notation w0 := W0.t.";
+for i = 1 to size do
+ pr " Definition w%i := zn2z w%i." i (i-1)
+done;
+pr "";
+
+pr " (** * The operation type classes for the word types *)
+";
+
+pr " Local Notation w0_op := W0.ops.";
+for i = 1 to min 3 size do
+ pr " Instance w%i_op : ZnZ.Ops w%i := mk_zn2z_ops w%i_op." i i (i-1)
+done;
+for i = 4 to size do
+ pr " Instance w%i_op : ZnZ.Ops w%i := mk_zn2z_ops_karatsuba w%i_op." i i (i-1)
+done;
+for i = size+1 to size+3 do
+ pr " Instance w%i_op : ZnZ.Ops (word w%i %i) := mk_zn2z_ops_karatsuba w%i_op." i size (i-size) (i-1)
+done;
+pr "";
pr " Section Make_op.";
- pr " Variable mk : forall w', znz_op w' -> znz_op (zn2z w').";
+ pr " Variable mk : forall w', ZnZ.Ops w' -> ZnZ.Ops (zn2z w').";
pr "";
- pr " Fixpoint make_op_aux (n:nat) : znz_op (word w%i (S n)):=" size;
- pr " match n return znz_op (word w%i (S n)) with" size;
+ pr " Fixpoint make_op_aux (n:nat) : ZnZ.Ops (word w%i (S n)):=" size;
+ pr " match n return ZnZ.Ops (word w%i (S n)) with" size;
pr " | O => w%i_op" (size+1);
pr " | S n1 =>";
- pr " match n1 return znz_op (word w%i (S (S n1))) with" size;
+ pr " match n1 return ZnZ.Ops (word w%i (S (S n1))) with" size;
pr " | O => w%i_op" (size+2);
pr " | S n2 =>";
- pr " match n2 return znz_op (word w%i (S (S (S n2)))) with" size;
+ pr " match n2 return ZnZ.Ops (word w%i (S (S (S n2)))) with" size;
pr " | O => w%i_op" (size+3);
pr " | S n3 => mk _ (mk _ (mk _ (make_op_aux n3)))";
pr " end";
@@ -110,2565 +98,912 @@ let _ =
pr "";
pr " End Make_op.";
pr "";
- pr " Definition omake_op := make_op_aux mk_zn2z_op_karatsuba.";
+ pr " Definition omake_op := make_op_aux mk_zn2z_ops_karatsuba.";
pr "";
pr "";
pr " Definition make_op_list := dmemo_list _ omake_op.";
pr "";
- pr " Definition make_op n := dmemo_get _ omake_op n make_op_list.";
- pr "";
- pr " Lemma make_op_omake: forall n, make_op n = omake_op n.";
- pr " intros n; unfold make_op, make_op_list.";
- pr " refine (dmemo_get_correct _ _ _).";
- pr " Qed.";
+ pr " Instance make_op n : ZnZ.Ops (word w%i (S n))" size;
+ pr " := dmemo_get _ omake_op n make_op_list.";
pr "";
- pr " Inductive %s_ :=" t;
- for i = 0 to size do
- pr " | %s%i : w%i -> %s_" c i i t
- done;
- pr " | %sn : forall n, word w%i (S n) -> %s_." c size t;
- pr "";
- pr " Definition %s := %s_." t t;
- pr "";
- pr " Definition w_0 := w0_op.(znz_0).";
- pr "";
+pr " Ltac unfold_ops := unfold omake_op, make_op_aux, w%i_op, w%i_op." (size+3) (size+2);
- for i = 0 to size do
- pr " Definition one%i := w%i_op.(znz_1)." i i
- done;
- pr "";
+pr
+"
+ Lemma make_op_omake: forall n, make_op n = omake_op n.
+ Proof.
+ intros n; unfold make_op, make_op_list.
+ refine (dmemo_get_correct _ _ _).
+ Qed.
+ Theorem make_op_S: forall n,
+ make_op (S n) = mk_zn2z_ops_karatsuba (make_op n).
+ Proof.
+ intros n. do 2 rewrite make_op_omake.
+ revert n. fix IHn 1.
+ do 3 (destruct n; [unfold_ops; reflexivity|]).
+ simpl mk_zn2z_ops_karatsuba. simpl word in *.
+ rewrite <- (IHn n). auto.
+ Qed.
- pr " Definition zero := %s0 w_0." c;
- pr " Definition one := %s0 one0." c;
- pr "";
+ (** * The main type [t], isomorphic with [exists n, word w0 n] *)
+";
- pr " Definition to_Z x :=";
- pr " match x with";
+ pr " Inductive t' :=";
for i = 0 to size do
- pr " | %s%i wx => w%i_op.(znz_to_Z) wx" c i i
+ pr " | N%i : w%i -> t'" i i
done;
- pr " | %sn n wx => (make_op n).(znz_to_Z) wx" c;
- pr " end.";
+ pr " | Nn : forall n, word w%i (S n) -> t'." size;
pr "";
-
- pr " Open Scope Z_scope.";
- pr " Notation \"[ x ]\" := (to_Z x).";
- pr "";
-
- pr " Definition to_N x := Zabs_N (to_Z x).";
+ pr " Definition t := t'.";
pr "";
-
- pr " Definition eq x y := (to_Z x = to_Z y).";
- pr "";
-
- pp " (* Regular make op (no karatsuba) *)";
- pp " Fixpoint nmake_op (ww:Type) (ww_op: znz_op ww) (n: nat) :";
- pp " znz_op (word ww n) :=";
- pp " match n return znz_op (word ww n) with";
- pp " O => ww_op";
- pp " | S n1 => mk_zn2z_op (nmake_op ww ww_op n1)";
- pp " end.";
- pp "";
- pp " (* Simplification by rewriting for nmake_op *)";
- pp " Theorem nmake_op_S: forall ww (w_op: znz_op ww) x,";
- pp " nmake_op _ w_op (S x) = mk_zn2z_op (nmake_op _ w_op x).";
- pp " auto.";
- pp " Qed.";
- pp "";
-
-
- pr " (* Eval and extend functions for each level *)";
- for i = 0 to size do
- pp " Let nmake_op%i := nmake_op _ w%i_op." i i;
- pp " Let eval%in n := znz_to_Z (nmake_op%i n)." i i;
- if i == 0 then
- pr " Let extend%i := DoubleBase.extend (WW w_0)." i
- else
- pr " Let extend%i := DoubleBase.extend (WW (W0: w%i))." i i;
- done;
+ pr " Bind Scope abstract_scope with t t'.";
pr "";
-
- pp " Theorem digits_doubled:forall n ww (w_op: znz_op ww),";
- pp " znz_digits (nmake_op _ w_op n) =";
- pp " DoubleBase.double_digits (znz_digits w_op) n.";
- pp " Proof.";
- pp " intros n; elim n; auto; clear n.";
- pp " intros n Hrec ww ww_op; simpl DoubleBase.double_digits.";
- pp " rewrite <- Hrec; auto.";
- pp " Qed.";
- pp "";
- pp " Theorem nmake_double: forall n ww (w_op: znz_op ww),";
- pp " znz_to_Z (nmake_op _ w_op n) =";
- pp " @DoubleBase.double_to_Z _ (znz_digits w_op) (znz_to_Z w_op) n.";
- pp " Proof.";
- pp " intros n; elim n; auto; clear n.";
- pp " intros n Hrec ww ww_op; simpl DoubleBase.double_to_Z; unfold zn2z_to_Z.";
- pp " rewrite <- Hrec; auto.";
- pp " unfold DoubleBase.double_wB; rewrite <- digits_doubled; auto.";
- pp " Qed.";
- pp "";
-
-
- pp " Theorem digits_nmake:forall n ww (w_op: znz_op ww),";
- pp " znz_digits (nmake_op _ w_op (S n)) =";
- pp " xO (znz_digits (nmake_op _ w_op n)).";
- pp " Proof.";
- pp " auto.";
- pp " Qed.";
- pp "";
-
-
- pp " Theorem znz_nmake_op: forall ww ww_op n xh xl,";
- pp " znz_to_Z (nmake_op ww ww_op (S n)) (WW xh xl) =";
- pp " znz_to_Z (nmake_op ww ww_op n) xh *";
- pp " base (znz_digits (nmake_op ww ww_op n)) +";
- pp " znz_to_Z (nmake_op ww ww_op n) xl.";
- pp " Proof.";
- pp " auto.";
- pp " Qed.";
- pp "";
-
- pp " Theorem make_op_S: forall n,";
- pp " make_op (S n) = mk_zn2z_op_karatsuba (make_op n).";
- pp " intro n.";
- pp " do 2 rewrite make_op_omake.";
- pp " pattern n; apply lt_wf_ind; clear n.";
- pp " intros n; case n; clear n.";
- pp " intros _; unfold omake_op, make_op_aux, w%i_op; apply refl_equal." (size + 2);
- pp " intros n; case n; clear n.";
- pp " intros _; unfold omake_op, make_op_aux, w%i_op; apply refl_equal." (size + 3);
- pp " intros n; case n; clear n.";
- pp " intros _; unfold omake_op, make_op_aux, w%i_op, w%i_op; apply refl_equal." (size + 3) (size + 2);
- pp " intros n Hrec.";
- pp " change (omake_op (S (S (S (S n))))) with";
- pp " (mk_zn2z_op_karatsuba (mk_zn2z_op_karatsuba (mk_zn2z_op_karatsuba (omake_op (S n))))).";
- pp " change (omake_op (S (S (S n)))) with";
- pp " (mk_zn2z_op_karatsuba (mk_zn2z_op_karatsuba (mk_zn2z_op_karatsuba (omake_op n)))).";
- pp " rewrite Hrec; auto with arith.";
- pp " Qed.";
- pp "";
-
-
- for i = 1 to size + 2 do
- pp " Let znz_to_Z_%i: forall x y," i;
- pp " znz_to_Z w%i_op (WW x y) =" i;
- pp " znz_to_Z w%i_op x * base (znz_digits w%i_op) + znz_to_Z w%i_op y." (i-1) (i-1) (i-1);
- pp " Proof.";
- pp " auto.";
- pp " Qed.";
- pp "";
- done;
-
- pp " Let znz_to_Z_n: forall n x y,";
- pp " znz_to_Z (make_op (S n)) (WW x y) =";
- pp " znz_to_Z (make_op n) x * base (znz_digits (make_op n)) + znz_to_Z (make_op n) y.";
- pp " Proof.";
- pp " intros n x y; rewrite make_op_S; auto.";
- pp " Qed.";
- pp "";
-
- pp " Let w0_spec: znz_spec w0_op := W0.w_spec.";
- for i = 1 to 3 do
- pp " Let w%i_spec: znz_spec w%i_op := mk_znz2_spec w%i_spec." i i (i-1)
- done;
- for i = 4 to size + 3 do
- pp " Let w%i_spec : znz_spec w%i_op := mk_znz2_karatsuba_spec w%i_spec." i i (i-1)
- done;
- pp "";
-
- pp " Let wn_spec: forall n, znz_spec (make_op n).";
- pp " intros n; elim n; clear n.";
- pp " exact w%i_spec." (size + 1);
- pp " intros n Hrec; rewrite make_op_S.";
- pp " exact (mk_znz2_karatsuba_spec Hrec).";
- pp " Qed.";
- pp "";
-
- for i = 0 to size do
- pr " Definition w%i_eq0 := w%i_op.(znz_eq0)." i i;
- pr " Let spec_w%i_eq0: forall x, if w%i_eq0 x then [%s%i x] = 0 else True." i i c i;
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; unfold w%i_eq0, to_Z; generalize (spec_eq0 w%i_spec x);" i i;
- pp " case znz_eq0; auto.";
- pp " Qed.";
- pr "";
- done;
+ pr " (** * A generic toolbox for building and deconstructing [t] *)";
pr "";
-
- for i = 0 to size do
- pp " Theorem digits_w%i: znz_digits w%i_op = znz_digits (nmake_op _ w0_op %i)." i i i;
- if i == 0 then
- pp " auto."
- else
- pp " rewrite digits_nmake; rewrite <- digits_w%i; auto." (i - 1);
- pp " Qed.";
- pp "";
- pp " Let spec_double_eval%in: forall n, eval%in n = DoubleBase.double_to_Z (znz_digits w%i_op) (znz_to_Z w%i_op) n." i i i i;
- pp " Proof.";
- pp " intros n; exact (nmake_double n w%i w%i_op)." i i;
- pp " Qed.";
- pp "";
- done;
-
- for i = 0 to size do
- for j = 0 to (size - i) do
- pp " Theorem digits_w%in%i: znz_digits w%i_op = znz_digits (nmake_op _ w%i_op %i)." i j (i + j) i j;
- pp " Proof.";
- if j == 0 then
- if i == 0 then
- pp " auto."
- else
- begin
- pp " apply trans_equal with (xO (znz_digits w%i_op))." (i + j -1);
- pp " auto.";
- pp " unfold nmake_op; auto.";
- end
- else
- begin
- pp " apply trans_equal with (xO (znz_digits w%i_op))." (i + j -1);
- pp " auto.";
- pp " rewrite digits_nmake.";
- pp " rewrite digits_w%in%i." i (j - 1);
- pp " auto.";
- end;
- pp " Qed.";
- pp "";
- pp " Let spec_eval%in%i: forall x, [%s%i x] = eval%in %i x." i j c (i + j) i j;
- pp " Proof.";
- if j == 0 then
- pp " intros x; rewrite spec_double_eval%in; unfold DoubleBase.double_to_Z, to_Z; auto." i
- else
- begin
- pp " intros x; case x.";
- pp " auto.";
- pp " intros xh xl; unfold to_Z; rewrite znz_to_Z_%i." (i + j);
- pp " rewrite digits_w%in%i." i (j - 1);
- pp " generalize (spec_eval%in%i); unfold to_Z; intros HH; repeat rewrite HH." i (j - 1);
- pp " unfold eval%in, nmake_op%i." i i;
- pp " rewrite (znz_nmake_op _ w%i_op %i); auto." i (j - 1);
- end;
- pp " Qed.";
- if i + j <> size then
- begin
- pp " Let spec_extend%in%i: forall x, [%s%i x] = [%s%i (extend%i %i x)]." i (i + j + 1) c i c (i + j + 1) i j;
- if j == 0 then
- begin
- pp " intros x; change (extend%i 0 x) with (WW (znz_0 w%i_op) x)." i (i + j);
- pp " unfold to_Z; rewrite znz_to_Z_%i." (i + j + 1);
- pp " rewrite (spec_0 w%i_spec); auto." (i + j);
- end
- else
- begin
- pp " intros x; change (extend%i %i x) with (WW (znz_0 w%i_op) (extend%i %i x))." i j (i + j) i (j - 1);
- pp " unfold to_Z; rewrite znz_to_Z_%i." (i + j + 1);
- pp " rewrite (spec_0 w%i_spec)." (i + j);
- pp " generalize (spec_extend%in%i x); unfold to_Z." i (i + j);
- pp " intros HH; rewrite <- HH; auto.";
- end;
- pp " Qed.";
- pp "";
- end;
- done;
-
- pp " Theorem digits_w%in%i: znz_digits w%i_op = znz_digits (nmake_op _ w%i_op %i)." i (size - i + 1) (size + 1) i (size - i + 1);
- pp " Proof.";
- pp " apply trans_equal with (xO (znz_digits w%i_op))." size;
- pp " auto.";
- pp " rewrite digits_nmake.";
- pp " rewrite digits_w%in%i." i (size - i);
- pp " auto.";
- pp " Qed.";
- pp "";
-
- pp " Let spec_eval%in%i: forall x, [%sn 0 x] = eval%in %i x." i (size - i + 1) c i (size - i + 1);
- pp " Proof.";
- pp " intros x; case x.";
- pp " auto.";
- pp " intros xh xl; unfold to_Z; rewrite znz_to_Z_%i." (size + 1);
- pp " rewrite digits_w%in%i." i (size - i);
- pp " generalize (spec_eval%in%i); unfold to_Z; intros HH; repeat rewrite HH." i (size - i);
- pp " unfold eval%in, nmake_op%i." i i;
- pp " rewrite (znz_nmake_op _ w%i_op %i); auto." i (size - i);
- pp " Qed.";
- pp "";
-
- pp " Let spec_eval%in%i: forall x, [%sn 1 x] = eval%in %i x." i (size - i + 2) c i (size - i + 2);
- pp " intros x; case x.";
- pp " auto.";
- pp " intros xh xl; unfold to_Z; rewrite znz_to_Z_%i." (size + 2);
- pp " rewrite digits_w%in%i." i (size + 1 - i);
- pp " generalize (spec_eval%in%i); unfold to_Z; change (make_op 0) with (w%i_op); intros HH; repeat rewrite HH." i (size + 1 - i) (size + 1);
- pp " unfold eval%in, nmake_op%i." i i;
- pp " rewrite (znz_nmake_op _ w%i_op %i); auto." i (size + 1 - i);
- pp " Qed.";
- pp "";
- done;
-
- pp " Let digits_w%in: forall n," size;
- pp " znz_digits (make_op n) = znz_digits (nmake_op _ w%i_op (S n))." size;
- pp " intros n; elim n; clear n.";
- pp " change (znz_digits (make_op 0)) with (xO (znz_digits w%i_op))." size;
- pp " rewrite nmake_op_S; apply sym_equal; auto.";
- pp " intros n Hrec.";
- pp " replace (znz_digits (make_op (S n))) with (xO (znz_digits (make_op n))).";
- pp " rewrite Hrec.";
- pp " rewrite nmake_op_S; apply sym_equal; auto.";
- pp " rewrite make_op_S; apply sym_equal; auto.";
- pp " Qed.";
- pp "";
-
- pp " Let spec_eval%in: forall n x, [%sn n x] = eval%in (S n) x." size c size;
- pp " intros n; elim n; clear n.";
- pp " exact spec_eval%in1." size;
- pp " intros n Hrec x; case x; clear x.";
- pp " unfold to_Z, eval%in, nmake_op%i." size size;
- pp " rewrite make_op_S; rewrite nmake_op_S; auto.";
- pp " intros xh xl.";
- pp " unfold to_Z in Hrec |- *.";
- pp " rewrite znz_to_Z_n.";
- pp " rewrite digits_w%in." size;
- pp " repeat rewrite Hrec.";
- pp " unfold eval%in, nmake_op%i." size size;
- pp " apply sym_equal; rewrite nmake_op_S; auto.";
- pp " Qed.";
- pp "";
-
- pp " Let spec_extend%in: forall n x, [%s%i x] = [%sn n (extend%i n x)]." size c size c size ;
- pp " intros n; elim n; clear n.";
- pp " intros x; change (extend%i 0 x) with (WW (znz_0 w%i_op) x)." size size;
- pp " unfold to_Z.";
- pp " change (make_op 0) with w%i_op." (size + 1);
- pp " rewrite znz_to_Z_%i; rewrite (spec_0 w%i_spec); auto." (size + 1) size;
- pp " intros n Hrec x.";
- pp " change (extend%i (S n) x) with (WW W0 (extend%i n x))." size size;
- pp " unfold to_Z in Hrec |- *; rewrite znz_to_Z_n; auto.";
- pp " rewrite <- Hrec.";
- pp " replace (znz_to_Z (make_op n) W0) with 0; auto.";
- pp " case n; auto; intros; rewrite make_op_S; auto.";
- pp " Qed.";
- pp "";
-
- pr " Theorem spec_pos: forall x, 0 <= [x].";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; clear x.";
- for i = 0 to size do
- pp " intros x; case (spec_to_Z w%i_spec x); auto." i;
- done;
- pp " intros n x; case (spec_to_Z (wn_spec n) x); auto.";
- pp " Qed.";
+ pr " Local Notation SizePlus n := %sn%s."
+ (iter_str size "(S ") (iter_str size ")");
+ pr " Local Notation Size := (SizePlus O).";
pr "";
- pp " Let spec_extendn_0: forall n wx, [%sn n (extend n _ wx)] = [%sn 0 wx]." c c;
- pp " intros n; elim n; auto.";
- pp " intros n1 Hrec wx; simpl extend; rewrite <- Hrec; auto.";
- pp " unfold to_Z.";
- pp " case n1; auto; intros n2; repeat rewrite make_op_S; auto.";
- pp " Qed.";
- pp "";
- pp " Let spec_extendn0_0: forall n wx, [%sn (S n) (WW W0 wx)] = [%sn n wx]." c c;
- pp " Proof.";
- pp " intros n x; unfold to_Z.";
- pp " rewrite znz_to_Z_n.";
- pp " rewrite <- (Zplus_0_l (znz_to_Z (make_op n) x)).";
- pp " apply (f_equal2 Zplus); auto.";
- pp " case n; auto.";
- pp " intros n1; rewrite make_op_S; auto.";
- pp " Qed.";
- pp "";
- pp " Let spec_extend_tr: forall m n (w: word _ (S n)),";
- pp " [%sn (m + n) (extend_tr w m)] = [%sn n w]." c c;
- pp " Proof.";
- pp " induction m; auto.";
- pp " intros n x; simpl extend_tr.";
- pp " simpl plus; rewrite spec_extendn0_0; auto.";
- pp " Qed.";
- pp "";
- pp " Let spec_cast_l: forall n m x1,";
- pp " [%sn (Max.max n m)" c;
- pp " (castm (diff_r n m) (extend_tr x1 (snd (diff n m))))] =";
- pp " [%sn n x1]." c;
- pp " Proof.";
- pp " intros n m x1; case (diff_r n m); simpl castm.";
- pp " rewrite spec_extend_tr; auto.";
- pp " Qed.";
- pp "";
- pp " Let spec_cast_r: forall n m x1,";
- pp " [%sn (Max.max n m)" c;
- pp " (castm (diff_l n m) (extend_tr x1 (fst (diff n m))))] =";
- pp " [%sn m x1]." c;
- pp " Proof.";
- pp " intros n m x1; case (diff_l n m); simpl castm.";
- pp " rewrite spec_extend_tr; auto.";
- pp " Qed.";
- pp "";
-
-
- pr " Section LevelAndIter.";
- pr "";
- pr " Variable res: Type.";
- pr " Variable xxx: res.";
- pr " Variable P: Z -> Z -> res -> Prop.";
- pr " (* Abstraction function for each level *)";
- for i = 0 to size do
- pr " Variable f%i: w%i -> w%i -> res." i i i;
- pr " Variable f%in: forall n, w%i -> word w%i (S n) -> res." i i i;
- pr " Variable fn%i: forall n, word w%i (S n) -> w%i -> res." i i i;
- pp " Variable Pf%i: forall x y, P [%s%i x] [%s%i y] (f%i x y)." i c i c i i;
- if i == size then
- begin
- pp " Variable Pf%in: forall n x y, P [%s%i x] (eval%in (S n) y) (f%in n x y)." i c i i i;
- pp " Variable Pfn%i: forall n x y, P (eval%in (S n) x) [%s%i y] (fn%i n x y)." i i c i i;
- end
- else
- begin
- pp " Variable Pf%in: forall n x y, Z_of_nat n <= %i -> P [%s%i x] (eval%in (S n) y) (f%in n x y)." i (size - i) c i i i;
- pp " Variable Pfn%i: forall n x y, Z_of_nat n <= %i -> P (eval%in (S n) x) [%s%i y] (fn%i n x y)." i (size - i) i c i i;
- end;
- pr "";
- done;
- pr " Variable fnn: forall n, word w%i (S n) -> word w%i (S n) -> res." size size;
- pp " Variable Pfnn: forall n x y, P [%sn n x] [%sn n y] (fnn n x y)." c c;
- pr " Variable fnm: forall n m, word w%i (S n) -> word w%i (S m) -> res." size size;
- pp " Variable Pfnm: forall n m x y, P [%sn n x] [%sn m y] (fnm n m x y)." c c;
- pr "";
- pr " (* Special zero functions *)";
- pr " Variable f0t: t_ -> res.";
- pp " Variable Pf0t: forall x, P 0 [x] (f0t x).";
- pr " Variable ft0: t_ -> res.";
- pp " Variable Pft0: forall x, P [x] 0 (ft0 x).";
+ pr " Tactic Notation \"do_size\" tactic(t) := do %i t." (size+1);
pr "";
-
- pr " (* We level the two arguments before applying *)";
- pr " (* the functions at each leval *)";
- pr " Definition same_level (x y: t_): res :=";
- pr0 " Eval lazy zeta beta iota delta [";
- for i = 0 to size do
- pr0 "extend%i " i;
- done;
- pr "";
- pr " DoubleBase.extend DoubleBase.extend_aux";
- pr " ] in";
- pr " match x, y with";
+ pr " Definition dom_t n := match n with";
for i = 0 to size do
- for j = 0 to i - 1 do
- pr " | %s%i wx, %s%i wy => f%i wx (extend%i %i wy)" c i c j i j (i - j -1);
- done;
- pr " | %s%i wx, %s%i wy => f%i wx wy" c i c i i;
- for j = i + 1 to size do
- pr " | %s%i wx, %s%i wy => f%i (extend%i %i wx) wy" c i c j j i (j - i - 1);
- done;
- if i == size then
- pr " | %s%i wx, %sn m wy => fnn m (extend%i m wx) wy" c size c size
- else
- pr " | %s%i wx, %sn m wy => fnn m (extend%i m (extend%i %i wx)) wy" c i c size i (size - i - 1);
+ pr " | %i => w%i" i i;
done;
- for i = 0 to size do
- if i == size then
- pr " | %sn n wx, %s%i wy => fnn n wx (extend%i n wy)" c c size size
- else
- pr " | %sn n wx, %s%i wy => fnn n wx (extend%i n (extend%i %i wy))" c c i size i (size - i - 1);
- done;
- pr " | %sn n wx, Nn m wy =>" c;
- pr " let mn := Max.max n m in";
- pr " let d := diff n m in";
- pr " fnn mn";
- pr " (castm (diff_r n m) (extend_tr wx (snd d)))";
- pr " (castm (diff_l n m) (extend_tr wy (fst d)))";
- pr " end.";
+ pr " | %sn => word w%i n" (if size=0 then "" else "SizePlus ") size;
+ pr " end.";
pr "";
- pp " Lemma spec_same_level: forall x y, P [x] [y] (same_level x y).";
- pp " Proof.";
- pp " intros x; case x; clear x; unfold same_level.";
- for i = 0 to size do
- pp " intros x y; case y; clear y.";
- for j = 0 to i - 1 do
- pp " intros y; rewrite spec_extend%in%i; apply Pf%i." j i i;
- done;
- pp " intros y; apply Pf%i." i;
- for j = i + 1 to size do
- pp " intros y; rewrite spec_extend%in%i; apply Pf%i." i j j;
- done;
- if i == size then
- pp " intros m y; rewrite (spec_extend%in m); apply Pfnn." size
- else
- pp " intros m y; rewrite spec_extend%in%i; rewrite (spec_extend%in m); apply Pfnn." i size size;
- done;
- pp " intros n x y; case y; clear y.";
- for i = 0 to size do
- if i == size then
- pp " intros y; rewrite (spec_extend%in n); apply Pfnn." size
- else
- pp " intros y; rewrite spec_extend%in%i; rewrite (spec_extend%in n); apply Pfnn." i size size;
- done;
- pp " intros m y; rewrite <- (spec_cast_l n m x);";
- pp " rewrite <- (spec_cast_r n m y); apply Pfnn.";
- pp " Qed.";
- pp "";
-
- pr " (* We level the two arguments before applying *)";
- pr " (* the functions at each level (special zero case) *)";
- pr " Definition same_level0 (x y: t_): res :=";
- pr0 " Eval lazy zeta beta iota delta [";
- for i = 0 to size do
- pr0 "extend%i " i;
- done;
- pr "";
- pr " DoubleBase.extend DoubleBase.extend_aux";
- pr " ] in";
- pr " match x with";
- for i = 0 to size do
- pr " | %s%i wx =>" c i;
- if i == 0 then
- pr " if w0_eq0 wx then f0t y else";
- pr " match y with";
- for j = 0 to i - 1 do
- pr " | %s%i wy =>" c j;
- if j == 0 then
- pr " if w0_eq0 wy then ft0 x else";
- pr " f%i wx (extend%i %i wy)" i j (i - j -1);
- done;
- pr " | %s%i wy => f%i wx wy" c i i;
- for j = i + 1 to size do
- pr " | %s%i wy => f%i (extend%i %i wx) wy" c j j i (j - i - 1);
- done;
- if i == size then
- pr " | %sn m wy => fnn m (extend%i m wx) wy" c size
- else
- pr " | %sn m wy => fnn m (extend%i m (extend%i %i wx)) wy" c size i (size - i - 1);
- pr" end";
- done;
- pr " | %sn n wx =>" c;
- pr " match y with";
- for i = 0 to size do
- pr " | %s%i wy =>" c i;
- if i == 0 then
- pr " if w0_eq0 wy then ft0 x else";
- if i == size then
- pr " fnn n wx (extend%i n wy)" size
- else
- pr " fnn n wx (extend%i n (extend%i %i wy))" size i (size - i - 1);
- done;
- pr " | %sn m wy =>" c;
- pr " let mn := Max.max n m in";
- pr " let d := diff n m in";
- pr " fnn mn";
- pr " (castm (diff_r n m) (extend_tr wx (snd d)))";
- pr " (castm (diff_l n m) (extend_tr wy (fst d)))";
- pr " end";
- pr " end.";
- pr "";
+pr
+" Instance dom_op n : ZnZ.Ops (dom_t n) | 10.
+ Proof.
+ do_size (destruct n; [simpl;auto with *|]).
+ unfold dom_t. auto with *.
+ Defined.
+";
- pp " Lemma spec_same_level0: forall x y, P [x] [y] (same_level0 x y).";
- pp " Proof.";
- pp " intros x; case x; clear x; unfold same_level0.";
- for i = 0 to size do
- pp " intros x.";
- if i == 0 then
- begin
- pp " generalize (spec_w0_eq0 x); case w0_eq0; intros H.";
- pp " intros y; rewrite H; apply Pf0t.";
- pp " clear H.";
- end;
- pp " intros y; case y; clear y.";
- for j = 0 to i - 1 do
- pp " intros y.";
- if j == 0 then
- begin
- pp " generalize (spec_w0_eq0 y); case w0_eq0; intros H.";
- pp " rewrite H; apply Pft0.";
- pp " clear H.";
- end;
- pp " rewrite spec_extend%in%i; apply Pf%i." j i i;
- done;
- pp " intros y; apply Pf%i." i;
- for j = i + 1 to size do
- pp " intros y; rewrite spec_extend%in%i; apply Pf%i." i j j;
- done;
- if i == size then
- pp " intros m y; rewrite (spec_extend%in m); apply Pfnn." size
- else
- pp " intros m y; rewrite spec_extend%in%i; rewrite (spec_extend%in m); apply Pfnn." i size size;
- done;
- pp " intros n x y; case y; clear y.";
+ pr " Definition iter_t {A:Type}(f : forall n, dom_t n -> A) : t -> A :=";
for i = 0 to size do
- pp " intros y.";
- if i = 0 then
- begin
- pp " generalize (spec_w0_eq0 y); case w0_eq0; intros H.";
- pp " rewrite H; apply Pft0.";
- pp " clear H.";
- end;
- if i == size then
- pp " rewrite (spec_extend%in n); apply Pfnn." size
- else
- pp " rewrite spec_extend%in%i; rewrite (spec_extend%in n); apply Pfnn." i size size;
+ pr " let f%i := f %i in" i i;
done;
- pp " intros m y; rewrite <- (spec_cast_l n m x);";
- pp " rewrite <- (spec_cast_r n m y); apply Pfnn.";
- pp " Qed.";
- pp "";
-
- pr " (* We iter the smaller argument with the bigger *)";
- pr " Definition iter (x y: t_): res :=";
- pr0 " Eval lazy zeta beta iota delta [";
+ pr " let fn n := f (SizePlus (S n)) in";
+ pr " fun x => match x with";
for i = 0 to size do
- pr0 "extend%i " i;
+ pr " | N%i wx => f%i wx" i i;
done;
- pr "";
- pr " DoubleBase.extend DoubleBase.extend_aux";
- pr " ] in";
- pr " match x, y with";
- for i = 0 to size do
- for j = 0 to i - 1 do
- pr " | %s%i wx, %s%i wy => fn%i %i wx wy" c i c j j (i - j - 1);
- done;
- pr " | %s%i wx, %s%i wy => f%i wx wy" c i c i i;
- for j = i + 1 to size do
- pr " | %s%i wx, %s%i wy => f%in %i wx wy" c i c j i (j - i - 1);
- done;
- if i == size then
- pr " | %s%i wx, %sn m wy => f%in m wx wy" c size c size
- else
- pr " | %s%i wx, %sn m wy => f%in m (extend%i %i wx) wy" c i c size i (size - i - 1);
- done;
- for i = 0 to size do
- if i == size then
- pr " | %sn n wx, %s%i wy => fn%i n wx wy" c c size size
- else
- pr " | %sn n wx, %s%i wy => fn%i n wx (extend%i %i wy)" c c i size i (size - i - 1);
- done;
- pr " | %sn n wx, %sn m wy => fnm n m wx wy" c c;
+ pr " | Nn n wx => fn n wx";
pr " end.";
pr "";
- pp " Ltac zg_tac := try";
- pp " (red; simpl Zcompare; auto;";
- pp " let t := fresh \"H\" in (intros t; discriminate t)).";
- pp "";
- pp " Lemma spec_iter: forall x y, P [x] [y] (iter x y).";
- pp " Proof.";
- pp " intros x; case x; clear x; unfold iter.";
- for i = 0 to size do
- pp " intros x y; case y; clear y.";
- for j = 0 to i - 1 do
- pp " intros y; rewrite spec_eval%in%i; apply (Pfn%i %i); zg_tac." j (i - j) j (i - j - 1);
- done;
- pp " intros y; apply Pf%i." i;
- for j = i + 1 to size do
- pp " intros y; rewrite spec_eval%in%i; apply (Pf%in %i); zg_tac." i (j - i) i (j - i - 1);
- done;
- if i == size then
- pp " intros m y; rewrite spec_eval%in; apply Pf%in." size size
- else
- pp " intros m y; rewrite spec_extend%in%i; rewrite spec_eval%in; apply Pf%in." i size size size;
- done;
- pp " intros n x y; case y; clear y.";
- for i = 0 to size do
- if i == size then
- pp " intros y; rewrite spec_eval%in; apply Pfn%i." size size
- else
- pp " intros y; rewrite spec_extend%in%i; rewrite spec_eval%in; apply Pfn%i." i size size size;
- done;
- pp " intros m y; apply Pfnm.";
- pp " Qed.";
- pp "";
-
-
- pr " (* We iter the smaller argument with the bigger (zero case) *)";
- pr " Definition iter0 (x y: t_): res :=";
- pr0 " Eval lazy zeta beta iota delta [";
- for i = 0 to size do
- pr0 "extend%i " i;
- done;
- pr "";
- pr " DoubleBase.extend DoubleBase.extend_aux";
- pr " ] in";
- pr " match x with";
- for i = 0 to size do
- pr " | %s%i wx =>" c i;
- if i == 0 then
- pr " if w0_eq0 wx then f0t y else";
- pr " match y with";
- for j = 0 to i - 1 do
- pr " | %s%i wy =>" c j;
- if j == 0 then
- pr " if w0_eq0 wy then ft0 x else";
- pr " fn%i %i wx wy" j (i - j - 1);
- done;
- pr " | %s%i wy => f%i wx wy" c i i;
- for j = i + 1 to size do
- pr " | %s%i wy => f%in %i wx wy" c j i (j - i - 1);
- done;
- if i == size then
- pr " | %sn m wy => f%in m wx wy" c size
- else
- pr " | %sn m wy => f%in m (extend%i %i wx) wy" c size i (size - i - 1);
- pr " end";
- done;
- pr " | %sn n wx =>" c;
- pr " match y with";
+ pr " Definition mk_t (n:nat) : dom_t n -> t :=";
+ pr " match n as n' return dom_t n' -> t with";
for i = 0 to size do
- pr " | %s%i wy =>" c i;
- if i == 0 then
- pr " if w0_eq0 wy then ft0 x else";
- if i == size then
- pr " fn%i n wx wy" size
- else
- pr " fn%i n wx (extend%i %i wy)" size i (size - i - 1);
+ pr " | %i => N%i" i i;
done;
- pr " | %sn m wy => fnm n m wx wy" c;
- pr " end";
+ pr " | %s(S n) => Nn n" (if size=0 then "" else "SizePlus ");
pr " end.";
pr "";
- pp " Lemma spec_iter0: forall x y, P [x] [y] (iter0 x y).";
- pp " Proof.";
- pp " intros x; case x; clear x; unfold iter0.";
- for i = 0 to size do
- pp " intros x.";
- if i == 0 then
- begin
- pp " generalize (spec_w0_eq0 x); case w0_eq0; intros H.";
- pp " intros y; rewrite H; apply Pf0t.";
- pp " clear H.";
- end;
- pp " intros y; case y; clear y.";
- for j = 0 to i - 1 do
- pp " intros y.";
- if j == 0 then
- begin
- pp " generalize (spec_w0_eq0 y); case w0_eq0; intros H.";
- pp " rewrite H; apply Pft0.";
- pp " clear H.";
- end;
- pp " rewrite spec_eval%in%i; apply (Pfn%i %i); zg_tac." j (i - j) j (i - j - 1);
- done;
- pp " intros y; apply Pf%i." i;
- for j = i + 1 to size do
- pp " intros y; rewrite spec_eval%in%i; apply (Pf%in %i); zg_tac." i (j - i) i (j - i - 1);
- done;
- if i == size then
- pp " intros m y; rewrite spec_eval%in; apply Pf%in." size size
- else
- pp " intros m y; rewrite spec_extend%in%i; rewrite spec_eval%in; apply Pf%in." i size size size;
- done;
- pp " intros n x y; case y; clear y.";
- for i = 0 to size do
- pp " intros y.";
- if i = 0 then
- begin
- pp " generalize (spec_w0_eq0 y); case w0_eq0; intros H.";
- pp " rewrite H; apply Pft0.";
- pp " clear H.";
- end;
- if i == size then
- pp " rewrite spec_eval%in; apply Pfn%i." size size
- else
- pp " rewrite spec_extend%in%i; rewrite spec_eval%in; apply Pfn%i." i size size size;
- done;
- pp " intros m y; apply Pfnm.";
- pp " Qed.";
- pp "";
-
-
- pr " End LevelAndIter.";
- pr "";
+pr
+" Definition level := iter_t (fun n _ => n).
+ Inductive View_t : t -> Prop :=
+ Mk_t : forall n (x : dom_t n), View_t (mk_t n x).
+
+ Lemma destr_t : forall x, View_t x.
+ Proof.
+ intros x. generalize (Mk_t (level x)). destruct x; simpl; auto.
+ Defined.
+
+ Lemma iter_mk_t : forall A (f:forall n, dom_t n -> A),
+ forall n x, iter_t f (mk_t n x) = f n x.
+ Proof.
+ do_size (destruct n; try reflexivity).
+ Qed.
+
+ (** * Projection to ZArith *)
+
+ Definition to_Z : t -> Z :=
+ Eval lazy beta iota delta [iter_t dom_t dom_op] in
+ iter_t (fun _ x => ZnZ.to_Z x).
+
+ Notation \"[ x ]\" := (to_Z x).
+
+ Theorem spec_mk_t : forall n (x:dom_t n), [mk_t n x] = ZnZ.to_Z x.
+ Proof.
+ intros. change to_Z with (iter_t (fun _ x => ZnZ.to_Z x)).
+ rewrite iter_mk_t; auto.
+ Qed.
+
+ (** * Regular make op, without memoization or karatsuba
+
+ This will normally never be used for actual computations,
+ but only for specification purpose when using
+ [word (dom_t n) m] intermediate values. *)
+
+ Fixpoint nmake_op (ww:Type) (ww_op: ZnZ.Ops ww) (n: nat) :
+ ZnZ.Ops (word ww n) :=
+ match n return ZnZ.Ops (word ww n) with
+ O => ww_op
+ | S n1 => mk_zn2z_ops (nmake_op ww ww_op n1)
+ end.
+
+ Let eval n m := ZnZ.to_Z (Ops:=nmake_op _ (dom_op n) m).
+
+ Theorem nmake_op_S: forall ww (w_op: ZnZ.Ops ww) x,
+ nmake_op _ w_op (S x) = mk_zn2z_ops (nmake_op _ w_op x).
+ Proof.
+ auto.
+ Qed.
+
+ Theorem digits_nmake_S :forall n ww (w_op: ZnZ.Ops ww),
+ ZnZ.digits (nmake_op _ w_op (S n)) =
+ xO (ZnZ.digits (nmake_op _ w_op n)).
+ Proof.
+ auto.
+ Qed.
+
+ Theorem digits_nmake : forall n ww (w_op: ZnZ.Ops ww),
+ ZnZ.digits (nmake_op _ w_op n) = Pos.shiftl_nat (ZnZ.digits w_op) n.
+ Proof.
+ induction n. auto.
+ intros ww ww_op. rewrite Pshiftl_nat_S, <- IHn; auto.
+ Qed.
+
+ Theorem nmake_double: forall n ww (w_op: ZnZ.Ops ww),
+ ZnZ.to_Z (Ops:=nmake_op _ w_op n) =
+ @DoubleBase.double_to_Z _ (ZnZ.digits w_op) (ZnZ.to_Z (Ops:=w_op)) n.
+ Proof.
+ intros n; elim n; auto; clear n.
+ intros n Hrec ww ww_op; simpl DoubleBase.double_to_Z; unfold zn2z_to_Z.
+ rewrite <- Hrec; auto.
+ unfold DoubleBase.double_wB; rewrite <- digits_nmake; auto.
+ Qed.
+
+ Theorem nmake_WW: forall ww ww_op n xh xl,
+ (ZnZ.to_Z (Ops:=nmake_op ww ww_op (S n)) (WW xh xl) =
+ ZnZ.to_Z (Ops:=nmake_op ww ww_op n) xh *
+ base (ZnZ.digits (nmake_op ww ww_op n)) +
+ ZnZ.to_Z (Ops:=nmake_op ww ww_op n) xl)%%Z.
+ Proof.
+ auto.
+ Qed.
+
+ (** * The specification proofs for the word operators *)
+";
+
+ if size <> 0 then
+ pr " Typeclasses Opaque %s." (iter_name 1 size "w" "");
+ pr "";
+
+ pr " Instance w0_spec: ZnZ.Specs w0_op := W0.specs.";
+ for i = 1 to min 3 size do
+ pr " Instance w%i_spec: ZnZ.Specs w%i_op := mk_zn2z_specs w%i_spec." i i (i-1)
+ done;
+ for i = 4 to size do
+ pr " Instance w%i_spec: ZnZ.Specs w%i_op := mk_zn2z_specs_karatsuba w%i_spec." i i (i-1)
+ done;
+ pr " Instance w%i_spec: ZnZ.Specs w%i_op := mk_zn2z_specs_karatsuba w%i_spec." (size+1) (size+1) size;
+
+
+pr "
+ Instance wn_spec (n:nat) : ZnZ.Specs (make_op n).
+ Proof.
+ induction n.
+ rewrite make_op_omake; simpl; auto with *.
+ rewrite make_op_S. exact (mk_zn2z_specs_karatsuba IHn).
+ Qed.
+
+ Instance dom_spec n : ZnZ.Specs (dom_op n) | 10.
+ Proof.
+ do_size (destruct n; auto with *). apply wn_spec.
+ Qed.
+
+ Let make_op_WW : forall n x y,
+ (ZnZ.to_Z (Ops:=make_op (S n)) (WW x y) =
+ ZnZ.to_Z (Ops:=make_op n) x * base (ZnZ.digits (make_op n))
+ + ZnZ.to_Z (Ops:=make_op n) y)%%Z.
+ Proof.
+ intros n x y; rewrite make_op_S; auto.
+ Qed.
+
+ (** * Zero *)
+
+ Definition zero0 : w0 := ZnZ.zero.
+
+ Definition zeron n : dom_t n :=
+ match n with
+ | O => zero0
+ | SizePlus (S n) => W0
+ | _ => W0
+ end.
+
+ Lemma spec_zeron : forall n, ZnZ.to_Z (zeron n) = 0%%Z.
+ Proof.
+ do_size (destruct n; [exact ZnZ.spec_0|]).
+ destruct n; auto. simpl. rewrite make_op_S. exact ZnZ.spec_0.
+ Qed.
+
+ (** * Digits *)
+
+ Lemma digits_make_op_0 : forall n,
+ ZnZ.digits (make_op n) = Pos.shiftl_nat (ZnZ.digits (dom_op Size)) (S n).
+ Proof.
+ induction n.
+ auto.
+ replace (ZnZ.digits (make_op (S n))) with (xO (ZnZ.digits (make_op n))).
+ rewrite IHn; auto.
+ rewrite make_op_S; auto.
+ Qed.
+
+ Lemma digits_make_op : forall n,
+ ZnZ.digits (make_op n) = Pos.shiftl_nat (ZnZ.digits w0_op) (SizePlus (S n)).
+ Proof.
+ intros. rewrite digits_make_op_0.
+ replace (SizePlus (S n)) with (S n + Size) by (rewrite <- plus_comm; auto).
+ rewrite Pshiftl_nat_plus. auto.
+ Qed.
+
+ Lemma digits_dom_op : forall n,
+ ZnZ.digits (dom_op n) = Pos.shiftl_nat (ZnZ.digits w0_op) n.
+ Proof.
+ do_size (destruct n; try reflexivity).
+ exact (digits_make_op n).
+ Qed.
+
+ Lemma digits_dom_op_nmake : forall n m,
+ ZnZ.digits (dom_op (m+n)) = ZnZ.digits (nmake_op _ (dom_op n) m).
+ Proof.
+ intros. rewrite digits_nmake, 2 digits_dom_op. apply Pshiftl_nat_plus.
+ Qed.
+
+ (** * Conversion between [zn2z (dom_t n)] and [dom_t (S n)].
+
+ These two types are provably equal, but not convertible,
+ hence we need some work. We now avoid using generic casts
+ (i.e. rewrite via proof of equalities in types), since
+ proving things with them is a mess.
+ *)
+
+ Definition succ_t n : zn2z (dom_t n) -> dom_t (S n) :=
+ match n with
+ | SizePlus (S _) => fun x => x
+ | _ => fun x => x
+ end.
+
+ Lemma spec_succ_t : forall n x,
+ ZnZ.to_Z (succ_t n x) =
+ zn2z_to_Z (base (ZnZ.digits (dom_op n))) ZnZ.to_Z x.
+ Proof.
+ do_size (destruct n ; [reflexivity|]).
+ intros. simpl. rewrite make_op_S. simpl. auto.
+ Qed.
+
+ Definition pred_t n : dom_t (S n) -> zn2z (dom_t n) :=
+ match n with
+ | SizePlus (S _) => fun x => x
+ | _ => fun x => x
+ end.
+
+ Lemma succ_pred_t : forall n x, succ_t n (pred_t n x) = x.
+ Proof.
+ do_size (destruct n ; [reflexivity|]). reflexivity.
+ Qed.
+
+ (** We can hence project from [zn2z (dom_t n)] to [t] : *)
+
+ Definition mk_t_S n (x : zn2z (dom_t n)) : t :=
+ mk_t (S n) (succ_t n x).
+
+ Lemma spec_mk_t_S : forall n x,
+ [mk_t_S n x] = zn2z_to_Z (base (ZnZ.digits (dom_op n))) ZnZ.to_Z x.
+ Proof.
+ intros. unfold mk_t_S. rewrite spec_mk_t. apply spec_succ_t.
+ Qed.
+
+ Lemma mk_t_S_level : forall n x, level (mk_t_S n x) = S n.
+ Proof.
+ intros. unfold mk_t_S, level. rewrite iter_mk_t; auto.
+ Qed.
+
+ (** * Conversion from [word (dom_t n) m] to [dom_t (m+n)].
+
+ Things are more complex here. We start with a naive version
+ that breaks zn2z-trees and reconstruct them. Doing this is
+ quite unfortunate, but I don't know how to fully avoid that.
+ (cast someday ?). Then we build an optimized version where
+ all basic cases (n<=6 or m<=7) are nicely handled.
+ *)
+
+ Definition zn2z_map {A} {B} (f:A->B) (x:zn2z A) : zn2z B :=
+ match x with
+ | W0 => W0
+ | WW h l => WW (f h) (f l)
+ end.
+
+ Lemma zn2z_map_id : forall A f (x:zn2z A), (forall u, f u = u) ->
+ zn2z_map f x = x.
+ Proof.
+ destruct x; auto; intros.
+ simpl; f_equal; auto.
+ Qed.
+
+ (** The naive version *)
+
+ Fixpoint plus_t n m : word (dom_t n) m -> dom_t (m+n) :=
+ match m as m' return word (dom_t n) m' -> dom_t (m'+n) with
+ | O => fun x => x
+ | S m => fun x => succ_t _ (zn2z_map (plus_t n m) x)
+ end.
+
+ Theorem spec_plus_t : forall n m (x:word (dom_t n) m),
+ ZnZ.to_Z (plus_t n m x) = eval n m x.
+ Proof.
+ unfold eval.
+ induction m.
+ simpl; auto.
+ intros.
+ simpl plus_t; simpl plus. rewrite spec_succ_t.
+ destruct x.
+ simpl; auto.
+ fold word in w, w0.
+ simpl. rewrite 2 IHm. f_equal. f_equal. f_equal.
+ apply digits_dom_op_nmake.
+ Qed.
+
+ Definition mk_t_w n m (x:word (dom_t n) m) : t :=
+ mk_t (m+n) (plus_t n m x).
+
+ Theorem spec_mk_t_w : forall n m (x:word (dom_t n) m),
+ [mk_t_w n m x] = eval n m x.
+ Proof.
+ intros. unfold mk_t_w. rewrite spec_mk_t. apply spec_plus_t.
+ Qed.
+
+ (** The optimized version.
+
+ NB: the last particular case for m could depend on n,
+ but it's simplier to just expand everywhere up to m=7
+ (cf [mk_t_w'] later).
+ *)
+
+ Definition plus_t' n : forall m, word (dom_t n) m -> dom_t (m+n) :=
+ match n return (forall m, word (dom_t n) m -> dom_t (m+n)) with
+ | SizePlus (S n') as n => plus_t n
+ | _ as n =>
+ fun m => match m return (word (dom_t n) m -> dom_t (m+n)) with
+ | SizePlus (S (S m')) as m => plus_t n m
+ | _ => fun x => x
+ end
+ end.
+
+ Lemma plus_t_equiv : forall n m x,
+ plus_t' n m x = plus_t n m x.
+ Proof.
+ (do_size try destruct n); try reflexivity;
+ (do_size try destruct m); try destruct m; try reflexivity;
+ simpl; symmetry; repeat (intros; apply zn2z_map_id; trivial).
+ Qed.
+
+ Lemma spec_plus_t' : forall n m x,
+ ZnZ.to_Z (plus_t' n m x) = eval n m x.
+ Proof.
+ intros; rewrite plus_t_equiv. apply spec_plus_t.
+ Qed.
+
+ (** Particular cases [Nk x] = eval i j x with specific k,i,j
+ can be solved by the following tactic *)
+
+ Ltac solve_eval :=
+ intros; rewrite <- spec_plus_t'; unfold to_Z; simpl dom_op; reflexivity.
+
+ (** The last particular case that remains useful *)
+
+ Lemma spec_eval_size : forall n x, [Nn n x] = eval Size (S n) x.
+ Proof.
+ induction n.
+ solve_eval.
+ destruct x as [ | xh xl ].
+ simpl. unfold eval. rewrite make_op_S. rewrite nmake_op_S. auto.
+ simpl word in xh, xl |- *.
+ unfold to_Z in *. rewrite make_op_WW.
+ unfold eval in *. rewrite nmake_WW.
+ f_equal; auto.
+ f_equal; auto.
+ f_equal.
+ rewrite <- digits_dom_op_nmake. rewrite plus_comm; auto.
+ Qed.
+
+ (** An optimized [mk_t_w].
+
+ We could say mk_t_w' := mk_t _ (plus_t' n m x)
+ (TODO: WHY NOT, BTW ??).
+ Instead we directly define functions for all intersting [n],
+ reverting to naive [mk_t_w] at places that should normally
+ never be used (see [mul] and [div_gt]).
+ *)
+";
+
+for i = 0 to size-1 do
+let pattern = (iter_str (size+1-i) "(S ") ^ "_" ^ (iter_str (size+1-i) ")") in
+pr
+" Let mk_t_%iw m := Eval cbv beta zeta iota delta [ mk_t plus ] in
+ match m return word w%i (S m) -> t with
+ | %s as p => mk_t_w %i (S p)
+ | p => mk_t (%i+p)
+ end.
+" i i pattern i (i+1)
+done;
+
+pr
+" Let mk_t_w' n : forall m, word (dom_t n) (S m) -> t :=
+ match n return (forall m, word (dom_t n) (S m) -> t) with";
+for i = 0 to size-1 do pr " | %i => mk_t_%iw" i i done;
+pr
+" | Size => Nn
+ | _ as n' => fun m => mk_t_w n' (S m)
+ end.
+";
+
+pr
+" Ltac solve_spec_mk_t_w' :=
+ rewrite <- spec_plus_t';
+ match goal with _ : word (dom_t ?n) ?m |- _ => apply (spec_mk_t (n+m)) end.
+
+ Theorem spec_mk_t_w' :
+ forall n m x, [mk_t_w' n m x] = eval n (S m) x.
+ Proof.
+ intros.
+ repeat (apply spec_mk_t_w || (destruct n;
+ [repeat (apply spec_mk_t_w || (destruct m; [solve_spec_mk_t_w'|]))|])).
+ apply spec_eval_size.
+ Qed.
+
+ (** * Extend : injecting [dom_t n] into [word (dom_t n) (S m)] *)
+
+ Definition extend n m (x:dom_t n) : word (dom_t n) (S m) :=
+ DoubleBase.extend_aux m (WW (zeron n) x).
+
+ Lemma spec_extend : forall n m x,
+ [mk_t n x] = eval n (S m) (extend n m x).
+ Proof.
+ intros. unfold eval, extend.
+ rewrite spec_mk_t.
+ assert (H : forall (x:dom_t n),
+ (ZnZ.to_Z (zeron n) * base (ZnZ.digits (dom_op n)) + ZnZ.to_Z x =
+ ZnZ.to_Z x)%%Z).
+ clear; intros; rewrite spec_zeron; auto.
+ rewrite <- (@DoubleBase.spec_extend _
+ (WW (zeron n)) (ZnZ.digits (dom_op n)) ZnZ.to_Z H m x).
+ simpl. rewrite digits_nmake, <- nmake_double. auto.
+ Qed.
+
+ (** A particular case of extend, used in [same_level]:
+ [extend_size] is [extend Size] *)
+
+ Definition extend_size := DoubleBase.extend (WW (W0:dom_t Size)).
+
+ Lemma spec_extend_size : forall n x, [mk_t Size x] = [Nn n (extend_size n x)].
+ Proof.
+ intros. rewrite spec_eval_size. apply (spec_extend Size n).
+ Qed.
+
+ (** Misc results about extensions *)
+
+ Let spec_extend_WW : forall n x,
+ [Nn (S n) (WW W0 x)] = [Nn n x].
+ Proof.
+ intros n x.
+ set (N:=SizePlus (S n)).
+ change ([Nn (S n) (extend N 0 x)]=[mk_t N x]).
+ rewrite (spec_extend N 0).
+ solve_eval.
+ Qed.
+
+ Let spec_extend_tr: forall m n w,
+ [Nn (m + n) (extend_tr w m)] = [Nn n w].
+ Proof.
+ induction m; auto.
+ intros n x; simpl extend_tr.
+ simpl plus; rewrite spec_extend_WW; auto.
+ Qed.
+
+ Let spec_cast_l: forall n m x1,
+ [Nn n x1] =
+ [Nn (Max.max n m) (castm (diff_r n m) (extend_tr x1 (snd (diff n m))))].
+ Proof.
+ intros n m x1; case (diff_r n m); simpl castm.
+ rewrite spec_extend_tr; auto.
+ Qed.
+
+ Let spec_cast_r: forall n m x1,
+ [Nn m x1] =
+ [Nn (Max.max n m) (castm (diff_l n m) (extend_tr x1 (fst (diff n m))))].
+ Proof.
+ intros n m x1; case (diff_l n m); simpl castm.
+ rewrite spec_extend_tr; auto.
+ Qed.
+
+ Ltac unfold_lets :=
+ match goal with
+ | h : _ |- _ => unfold h; clear h; unfold_lets
+ | _ => idtac
+ end.
+
+ (** * [same_level]
+
+ Generic binary operator construction, by extending the smaller
+ argument to the level of the other.
+ *)
+
+ Section SameLevel.
+
+ Variable res: Type.
+ Variable P : Z -> Z -> res -> Prop.
+ Variable f : forall n, dom_t n -> dom_t n -> res.
+ Variable Pf : forall n x y, P (ZnZ.to_Z x) (ZnZ.to_Z y) (f n x y).
+";
+
+for i = 0 to size do
+pr " Let f%i : w%i -> w%i -> res := f %i." i i i i
+done;
+pr
+" Let fn n := f (SizePlus (S n)).
+
+ Let Pf' :
+ forall n x y u v, u = [mk_t n x] -> v = [mk_t n y] -> P u v (f n x y).
+ Proof.
+ intros. subst. rewrite 2 spec_mk_t. apply Pf.
+ Qed.
+";
+
+let ext i j s =
+ if j <= i then s else Printf.sprintf "(extend %i %i %s)" i (j-i-1) s
+in
+
+pr " Notation same_level_folded := (fun x y => match x, y with";
+for i = 0 to size do
+ for j = 0 to size do
+ pr " | N%i wx, N%i wy => f%i %s %s" i j (max i j) (ext i j "wx") (ext j i "wy")
+ done;
+ pr " | N%i wx, Nn m wy => fn m (extend_size m %s) wy" i (ext i size "wx")
+done;
+for i = 0 to size do
+ pr " | Nn n wx, N%i wy => fn n wx (extend_size n %s)" i (ext i size "wy")
+done;
+pr
+" | Nn n wx, Nn m wy =>
+ let mn := Max.max n m in
+ let d := diff n m in
+ fn mn
+ (castm (diff_r n m) (extend_tr wx (snd d)))
+ (castm (diff_l n m) (extend_tr wy (fst d)))
+ end).
+";
+
+pr
+" Definition same_level := Eval lazy beta iota delta
+ [ DoubleBase.extend DoubleBase.extend_aux extend zeron ]
+ in same_level_folded.
+
+ Lemma spec_same_level_0: forall x y, P [x] [y] (same_level x y).
+ Proof.
+ change same_level with same_level_folded. unfold_lets.
+ destruct x, y; apply Pf'; simpl mk_t; rewrite <- ?spec_extend_size;
+ match goal with
+ | |- context [ extend ?n ?m _ ] => apply (spec_extend n m)
+ | |- context [ castm _ _ ] => apply spec_cast_l || apply spec_cast_r
+ | _ => reflexivity
+ end.
+ Qed.
+
+ End SameLevel.
+
+ Arguments same_level [res] f x y.
+
+ Theorem spec_same_level_dep :
+ forall res
+ (P : nat -> Z -> Z -> res -> Prop)
+ (Pantimon : forall n m z z' r, n <= m -> P m z z' r -> P n z z' r)
+ (f : forall n, dom_t n -> dom_t n -> res)
+ (Pf: forall n x y, P n (ZnZ.to_Z x) (ZnZ.to_Z y) (f n x y)),
+ forall x y, P (level x) [x] [y] (same_level f x y).
+ Proof.
+ intros res P Pantimon f Pf.
+ set (f' := fun n x y => (n, f n x y)).
+ set (P' := fun z z' r => P (fst r) z z' (snd r)).
+ assert (FST : forall x y, level x <= fst (same_level f' x y))
+ by (destruct x, y; simpl; omega with * ).
+ assert (SND : forall x y, same_level f x y = snd (same_level f' x y))
+ by (destruct x, y; reflexivity).
+ intros. eapply Pantimon; [eapply FST|].
+ rewrite SND. eapply (@spec_same_level_0 _ P' f'); eauto.
+ Qed.
+
+ (** * [iter]
+
+ Generic binary operator construction, by splitting the larger
+ argument in blocks and applying the smaller argument to them.
+ *)
+
+ Section Iter.
+
+ Variable res: Type.
+ Variable P: Z -> Z -> res -> Prop.
+
+ Variable f : forall n, dom_t n -> dom_t n -> res.
+ Variable Pf : forall n x y, P (ZnZ.to_Z x) (ZnZ.to_Z y) (f n x y).
+
+ Variable fd : forall n m, dom_t n -> word (dom_t n) (S m) -> res.
+ Variable fg : forall n m, word (dom_t n) (S m) -> dom_t n -> res.
+ Variable Pfd : forall n m x y, P (ZnZ.to_Z x) (eval n (S m) y) (fd n m x y).
+ Variable Pfg : forall n m x y, P (eval n (S m) x) (ZnZ.to_Z y) (fg n m x y).
+
+ Variable fnm: forall n m, word (dom_t Size) (S n) -> word (dom_t Size) (S m) -> res.
+ Variable Pfnm: forall n m x y, P [Nn n x] [Nn m y] (fnm n m x y).
+
+ Let Pf' :
+ forall n x y u v, u = [mk_t n x] -> v = [mk_t n y] -> P u v (f n x y).
+ Proof.
+ intros. subst. rewrite 2 spec_mk_t. apply Pf.
+ Qed.
+
+ Let Pfd' : forall n m x y u v, u = [mk_t n x] -> v = eval n (S m) y ->
+ P u v (fd n m x y).
+ Proof.
+ intros. subst. rewrite spec_mk_t. apply Pfd.
+ Qed.
+
+ Let Pfg' : forall n m x y u v, u = eval n (S m) x -> v = [mk_t n y] ->
+ P u v (fg n m x y).
+ Proof.
+ intros. subst. rewrite spec_mk_t. apply Pfg.
+ Qed.
+";
+
+for i = 0 to size do
+pr " Let f%i := f %i." i i
+done;
+
+for i = 0 to size do
+pr " Let f%in := fd %i." i i;
+pr " Let fn%i := fg %i." i i;
+done;
+
+pr " Notation iter_folded := (fun x y => match x, y with";
+for i = 0 to size do
+ for j = 0 to size do
+ pr " | N%i wx, N%i wy => f%s wx wy" i j
+ (if i = j then string_of_int i
+ else if i < j then string_of_int i ^ "n " ^ string_of_int (j-i-1)
+ else "n" ^ string_of_int j ^ " " ^ string_of_int (i-j-1))
+ done;
+ pr " | N%i wx, Nn m wy => f%in m %s wy" i size (ext i size "wx")
+done;
+for i = 0 to size do
+ pr " | Nn n wx, N%i wy => fn%i n wx %s" i size (ext i size "wy")
+done;
+pr
+" | Nn n wx, Nn m wy => fnm n m wx wy
+ end).
+";
+
+pr
+" Definition iter := Eval lazy beta iota delta
+ [extend DoubleBase.extend DoubleBase.extend_aux zeron]
+ in iter_folded.
+
+ Lemma spec_iter: forall x y, P [x] [y] (iter x y).
+ Proof.
+ change iter with iter_folded; unfold_lets.
+ destruct x; destruct y; apply Pf' || apply Pfd' || apply Pfg' || apply Pfnm;
+ simpl mk_t;
+ match goal with
+ | |- ?x = ?x => reflexivity
+ | |- [Nn _ _] = _ => apply spec_eval_size
+ | |- context [extend ?n ?m _] => apply (spec_extend n m)
+ | _ => idtac
+ end;
+ unfold to_Z; rewrite <- spec_plus_t'; simpl dom_op; reflexivity.
+ Qed.
+
+ End Iter.
+";
+
+pr
+" Definition switch
+ (P:nat->Type)%s
+ (fn:forall n, P n) n :=
+ match n return P n with"
+ (iter_str_gen size (fun i -> Printf.sprintf "(f%i:P %i)" i i));
+for i = 0 to size do pr " | %i => f%i" i i done;
+pr
+" | n => fn n
+ end.
+";
+
+pr
+" Lemma spec_switch : forall P (f:forall n, P n) n,
+ switch P %sf n = f n.
+ Proof.
+ repeat (destruct n; try reflexivity).
+ Qed.
+" (iter_str_gen size (fun i -> Printf.sprintf "(f %i) " i));
+
+pr
+" (** * [iter_sym]
+
+ A variant of [iter] for symmetric functions, or pseudo-symmetric
+ functions (when f y x can be deduced from f x y).
+ *)
+
+ Section IterSym.
+
+ Variable res: Type.
+ Variable P: Z -> Z -> res -> Prop.
+
+ Variable f : forall n, dom_t n -> dom_t n -> res.
+ Variable Pf : forall n x y, P (ZnZ.to_Z x) (ZnZ.to_Z y) (f n x y).
+
+ Variable fg : forall n m, word (dom_t n) (S m) -> dom_t n -> res.
+ Variable Pfg : forall n m x y, P (eval n (S m) x) (ZnZ.to_Z y) (fg n m x y).
+
+ Variable fnm: forall n m, word (dom_t Size) (S n) -> word (dom_t Size) (S m) -> res.
+ Variable Pfnm: forall n m x y, P [Nn n x] [Nn m y] (fnm n m x y).
+
+ Variable opp: res -> res.
+ Variable Popp : forall u v r, P u v r -> P v u (opp r).
+";
+
+for i = 0 to size do
+pr " Let f%i := f %i." i i
+done;
+
+for i = 0 to size do
+pr " Let fn%i := fg %i." i i;
+done;
+
+pr " Let f' := switch _ %s f." (iter_name 0 size "f" "");
+pr " Let fg' := switch _ %s fg." (iter_name 0 size "fn" "");
+
+pr
+" Local Notation iter_sym_folded :=
+ (iter res f' (fun n m x y => opp (fg' n m y x)) fg' fnm).
+
+ Definition iter_sym :=
+ Eval lazy beta zeta iota delta [iter f' fg' switch] in iter_sym_folded.
+
+ Lemma spec_iter_sym: forall x y, P [x] [y] (iter_sym x y).
+ Proof.
+ intros. change iter_sym with iter_sym_folded. apply spec_iter; clear x y.
+ unfold_lets.
+ intros. rewrite spec_switch. auto.
+ intros. apply Popp. unfold_lets. rewrite spec_switch; auto.
+ intros. unfold_lets. rewrite spec_switch; auto.
+ auto.
+ Qed.
+
+ End IterSym.
+
+ (** * Reduction
+
+ [reduce] can be used instead of [mk_t], it will choose the
+ lowest possible level. NB: We only search and remove leftmost
+ W0's via ZnZ.eq0, any non-W0 block ends the process, even
+ if its value is 0.
+ *)
+
+ (** First, a direct version ... *)
+
+ Fixpoint red_t n : dom_t n -> t :=
+ match n return dom_t n -> t with
+ | O => N0
+ | S n => fun x =>
+ let x' := pred_t n x in
+ reduce_n1 _ _ (N0 zero0) ZnZ.eq0 (red_t n) (mk_t_S n) x'
+ end.
+
+ Lemma spec_red_t : forall n x, [red_t n x] = [mk_t n x].
+ Proof.
+ induction n.
+ reflexivity.
+ intros.
+ simpl red_t. unfold reduce_n1.
+ rewrite <- (succ_pred_t n x) at 2.
+ remember (pred_t n x) as x'.
+ rewrite spec_mk_t, spec_succ_t.
+ destruct x' as [ | xh xl]. simpl. apply ZnZ.spec_0.
+ generalize (ZnZ.spec_eq0 xh); case ZnZ.eq0; intros H.
+ rewrite IHn, spec_mk_t. simpl. rewrite H; auto.
+ apply spec_mk_t_S.
+ Qed.
+
+ (** ... then a specialized one *)
+";
+
+for i = 0 to size do
+pr " Definition eq0%i := @ZnZ.eq0 _ w%i_op." i i;
+done;
+
+pr "
+ Definition reduce_0 := N0.";
+for i = 1 to size do
+ pr " Definition reduce_%i :=" i;
+ pr " Eval lazy beta iota delta [reduce_n1] in";
+ pr " reduce_n1 _ _ (N0 zero0) eq0%i reduce_%i N%i." (i-1) (i-1) i
+done;
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Reduction *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- pr " Definition reduce_0 (x:w) := %s0 x." c;
- pr " Definition reduce_1 :=";
- pr " Eval lazy beta iota delta[reduce_n1] in";
- pr " reduce_n1 _ _ zero w0_eq0 %s0 %s1." c c;
- for i = 2 to size do
- pr " Definition reduce_%i :=" i;
- pr " Eval lazy beta iota delta[reduce_n1] in";
- pr " reduce_n1 _ _ zero w%i_eq0 reduce_%i %s%i."
- (i-1) (i-1) c i
- done;
pr " Definition reduce_%i :=" (size+1);
- pr " Eval lazy beta iota delta[reduce_n1] in";
- pr " reduce_n1 _ _ zero w%i_eq0 reduce_%i (%sn 0)."
- size size c;
+ pr " Eval lazy beta iota delta [reduce_n1] in";
+ pr " reduce_n1 _ _ (N0 zero0) eq0%i reduce_%i (Nn 0)." size size;
pr " Definition reduce_n n :=";
- pr " Eval lazy beta iota delta[reduce_n] in";
- pr " reduce_n _ _ zero reduce_%i %sn n." (size + 1) c;
- pr "";
-
- pp " Let spec_reduce_0: forall x, [reduce_0 x] = [%s0 x]." c;
- pp " Proof.";
- pp " intros x; unfold to_Z, reduce_0.";
- pp " auto.";
- pp " Qed.";
- pp "";
-
- for i = 1 to size + 1 do
- if i == size + 1 then
- pp " Let spec_reduce_%i: forall x, [reduce_%i x] = [%sn 0 x]." i i c
- else
- pp " Let spec_reduce_%i: forall x, [reduce_%i x] = [%s%i x]." i i c i;
- pp " Proof.";
- pp " intros x; case x; unfold reduce_%i." i;
- pp " exact (spec_0 w0_spec).";
- pp " intros x1 y1.";
- pp " generalize (spec_w%i_eq0 x1);" (i - 1);
- pp " case w%i_eq0; intros H1; auto." (i - 1);
- if i <> 1 then
- pp " rewrite spec_reduce_%i." (i - 1);
- pp " unfold to_Z; rewrite znz_to_Z_%i." i;
- pp " unfold to_Z in H1; rewrite H1; auto.";
- pp " Qed.";
- pp "";
- done;
-
- pp " Let spec_reduce_n: forall n x, [reduce_n n x] = [%sn n x]." c;
- pp " Proof.";
- pp " intros n; elim n; simpl reduce_n.";
- pp " intros x; rewrite <- spec_reduce_%i; auto." (size + 1);
- pp " intros n1 Hrec x; case x.";
- pp " unfold to_Z; rewrite make_op_S; auto.";
- pp " exact (spec_0 w0_spec).";
- pp " intros x1 y1; case x1; auto.";
- pp " rewrite Hrec.";
- pp " rewrite spec_extendn0_0; auto.";
- pp " Qed.";
- pp "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Successor *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_succ_c := w%i_op.(znz_succ_c)." i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_succ := w%i_op.(znz_succ)." i i
- done;
- pr "";
-
- pr " Definition succ x :=";
- pr " match x with";
- for i = 0 to size-1 do
- pr " | %s%i wx =>" c i;
- pr " match w%i_succ_c wx with" i;
- pr " | C0 r => %s%i r" c i;
- pr " | C1 r => %s%i (WW one%i r)" c (i+1) i;
- pr " end";
- done;
- pr " | %s%i wx =>" c size;
- pr " match w%i_succ_c wx with" size;
- pr " | C0 r => %s%i r" c size;
- pr " | C1 r => %sn 0 (WW one%i r)" c size ;
- pr " end";
- pr " | %sn n wx =>" c;
- pr " let op := make_op n in";
- pr " match op.(znz_succ_c) wx with";
- pr " | C0 r => %sn n r" c;
- pr " | C1 r => %sn (S n) (WW op.(znz_1) r)" c;
- pr " end";
- pr " end.";
- pr "";
-
- pr " Theorem spec_succ: forall n, [succ n] = [n] + 1.";
- pa " Admitted.";
- pp " Proof.";
- pp " intros n; case n; unfold succ, to_Z.";
- for i = 0 to size do
- pp " intros n1; generalize (spec_succ_c w%i_spec n1);" i;
- pp " unfold succ, to_Z, w%i_succ_c; case znz_succ_c; auto." i;
- pp " intros ww H; rewrite <- H.";
- pp " (rewrite znz_to_Z_%i; unfold interp_carry;" (i + 1);
- pp " apply f_equal2 with (f := Zplus); auto;";
- pp " apply f_equal2 with (f := Zmult); auto;";
- pp " exact (spec_1 w%i_spec))." i;
- done;
- pp " intros k n1; generalize (spec_succ_c (wn_spec k) n1).";
- pp " unfold succ, to_Z; case znz_succ_c; auto.";
- pp " intros ww H; rewrite <- H.";
- pp " (rewrite (znz_to_Z_n k); unfold interp_carry;";
- pp " apply f_equal2 with (f := Zplus); auto;";
- pp " apply f_equal2 with (f := Zmult); auto;";
- pp " exact (spec_1 (wn_spec k))).";
- pp " Qed.";
- pr "";
-
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Adddition *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_add_c := znz_add_c w%i_op." i i;
- pr " Definition w%i_add x y :=" i;
- pr " match w%i_add_c x y with" i;
- pr " | C0 r => %s%i r" c i;
- if i == size then
- pr " | C1 r => %sn 0 (WW one%i r)" c size
- else
- pr " | C1 r => %s%i (WW one%i r)" c (i + 1) i;
- pr " end.";
- pr "";
- done ;
- pr " Definition addn n (x y : word w%i (S n)) :=" size;
- pr " let op := make_op n in";
- pr " match op.(znz_add_c) x y with";
- pr " | C0 r => %sn n r" c;
- pr " | C1 r => %sn (S n) (WW op.(znz_1) r) end." c;
- pr "";
-
-
- for i = 0 to size do
- pp " Let spec_w%i_add: forall x y, [w%i_add x y] = [%s%i x] + [%s%i y]." i i c i c i;
- pp " Proof.";
- pp " intros n m; unfold to_Z, w%i_add, w%i_add_c." i i;
- pp " generalize (spec_add_c w%i_spec n m); case znz_add_c; auto." i;
- pp " intros ww H; rewrite <- H.";
- pp " rewrite znz_to_Z_%i; unfold interp_carry;" (i + 1);
- pp " apply f_equal2 with (f := Zplus); auto;";
- pp " apply f_equal2 with (f := Zmult); auto;";
- pp " exact (spec_1 w%i_spec)." i;
- pp " Qed.";
- pp "";
- done;
- pp " Let spec_wn_add: forall n x y, [addn n x y] = [%sn n x] + [%sn n y]." c c;
- pp " Proof.";
- pp " intros k n m; unfold to_Z, addn.";
- pp " generalize (spec_add_c (wn_spec k) n m); case znz_add_c; auto.";
- pp " intros ww H; rewrite <- H.";
- pp " rewrite (znz_to_Z_n k); unfold interp_carry;";
- pp " apply f_equal2 with (f := Zplus); auto;";
- pp " apply f_equal2 with (f := Zmult); auto;";
- pp " exact (spec_1 (wn_spec k)).";
- pp " Qed.";
-
- pr " Definition add := Eval lazy beta delta [same_level] in";
- pr0 " (same_level t_ ";
- for i = 0 to size do
- pr0 "w%i_add " i;
- done;
- pr "addn).";
- pr "";
-
- pr " Theorem spec_add: forall x y, [add x y] = [x] + [y].";
- pa " Admitted.";
- pp " Proof.";
- pp " unfold add.";
- pp " generalize (spec_same_level t_ (fun x y res => [res] = x + y)).";
- pp " unfold same_level; intros HH; apply HH; clear HH.";
- for i = 0 to size do
- pp " exact spec_w%i_add." i;
- done;
- pp " exact spec_wn_add.";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Predecessor *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_pred_c := w%i_op.(znz_pred_c)." i i
- done;
- pr "";
-
- pr " Definition pred x :=";
- pr " match x with";
- for i = 0 to size do
- pr " | %s%i wx =>" c i;
- pr " match w%i_pred_c wx with" i;
- pr " | C0 r => reduce_%i r" i;
- pr " | C1 r => zero";
- pr " end";
- done;
- pr " | %sn n wx =>" c;
- pr " let op := make_op n in";
- pr " match op.(znz_pred_c) wx with";
- pr " | C0 r => reduce_n n r";
- pr " | C1 r => zero";
- pr " end";
- pr " end.";
- pr "";
-
- pr " Theorem spec_pred_pos : forall x, 0 < [x] -> [pred x] = [x] - 1.";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold pred.";
- for i = 0 to size do
- pp " intros x1 H1; unfold w%i_pred_c;" i;
- pp " generalize (spec_pred_c w%i_spec x1); case znz_pred_c; intros y1." i;
- pp " rewrite spec_reduce_%i; auto." i;
- pp " unfold interp_carry; unfold to_Z.";
- pp " case (spec_to_Z w%i_spec x1); intros HH1 HH2." i;
- pp " case (spec_to_Z w%i_spec y1); intros HH3 HH4 HH5." i;
- pp " assert (znz_to_Z w%i_op x1 - 1 < 0); auto with zarith." i;
- pp " unfold to_Z in H1; auto with zarith.";
- done;
- pp " intros n x1 H1;";
- pp " generalize (spec_pred_c (wn_spec n) x1); case znz_pred_c; intros y1.";
- pp " rewrite spec_reduce_n; auto.";
- pp " unfold interp_carry; unfold to_Z.";
- pp " case (spec_to_Z (wn_spec n) x1); intros HH1 HH2.";
- pp " case (spec_to_Z (wn_spec n) y1); intros HH3 HH4 HH5.";
- pp " assert (znz_to_Z (make_op n) x1 - 1 < 0); auto with zarith.";
- pp " unfold to_Z in H1; auto with zarith.";
- pp " Qed.";
- pp "";
-
- pp " Let spec_pred0: forall x, [x] = 0 -> [pred x] = 0.";
- pp " Proof.";
- pp " intros x; case x; unfold pred.";
- for i = 0 to size do
- pp " intros x1 H1; unfold w%i_pred_c;" i;
- pp " generalize (spec_pred_c w%i_spec x1); case znz_pred_c; intros y1." i;
- pp " unfold interp_carry; unfold to_Z.";
- pp " unfold to_Z in H1; auto with zarith.";
- pp " case (spec_to_Z w%i_spec y1); intros HH3 HH4; auto with zarith." i;
- pp " intros; exact (spec_0 w0_spec).";
- done;
- pp " intros n x1 H1;";
- pp " generalize (spec_pred_c (wn_spec n) x1); case znz_pred_c; intros y1.";
- pp " unfold interp_carry; unfold to_Z.";
- pp " unfold to_Z in H1; auto with zarith.";
- pp " case (spec_to_Z (wn_spec n) y1); intros HH3 HH4; auto with zarith.";
- pp " intros; exact (spec_0 w0_spec).";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Subtraction *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_sub_c := w%i_op.(znz_sub_c)." i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_sub x y :=" i;
- pr " match w%i_sub_c x y with" i;
- pr " | C0 r => reduce_%i r" i;
- pr " | C1 r => zero";
- pr " end."
- done;
- pr "";
-
- pr " Definition subn n (x y : word w%i (S n)) :=" size;
- pr " let op := make_op n in";
- pr " match op.(znz_sub_c) x y with";
- pr " | C0 r => %sn n r" c;
- pr " | C1 r => N0 w_0";
- pr " end.";
- pr "";
-
- for i = 0 to size do
- pp " Let spec_w%i_sub: forall x y, [%s%i y] <= [%s%i x] -> [w%i_sub x y] = [%s%i x] - [%s%i y]." i c i c i i c i c i;
- pp " Proof.";
- pp " intros n m; unfold w%i_sub, w%i_sub_c." i i;
- pp " generalize (spec_sub_c w%i_spec n m); case znz_sub_c;" i;
- if i == 0 then
- pp " intros x; auto."
- else
- pp " intros x; try rewrite spec_reduce_%i; auto." i;
- pp " unfold interp_carry; unfold zero, w_0, to_Z.";
- pp " rewrite (spec_0 w0_spec).";
- pp " case (spec_to_Z w%i_spec x); intros; auto with zarith." i;
- pp " Qed.";
- pp "";
- done;
-
- pp " Let spec_wn_sub: forall n x y, [%sn n y] <= [%sn n x] -> [subn n x y] = [%sn n x] - [%sn n y]." c c c c;
- pp " Proof.";
- pp " intros k n m; unfold subn.";
- pp " generalize (spec_sub_c (wn_spec k) n m); case znz_sub_c;";
- pp " intros x; auto.";
- pp " unfold interp_carry, to_Z.";
- pp " case (spec_to_Z (wn_spec k) x); intros; auto with zarith.";
- pp " Qed.";
- pp "";
-
- pr " Definition sub := Eval lazy beta delta [same_level] in";
- pr0 " (same_level t_ ";
- for i = 0 to size do
- pr0 "w%i_sub " i;
- done;
- pr "subn).";
- pr "";
-
- pr " Theorem spec_sub_pos : forall x y, [y] <= [x] -> [sub x y] = [x] - [y].";
- pa " Admitted.";
- pp " Proof.";
- pp " unfold sub.";
- pp " generalize (spec_same_level t_ (fun x y res => y <= x -> [res] = x - y)).";
- pp " unfold same_level; intros HH; apply HH; clear HH.";
- for i = 0 to size do
- pp " exact spec_w%i_sub." i;
- done;
- pp " exact spec_wn_sub.";
- pp " Qed.";
- pr "";
-
- for i = 0 to size do
- pp " Let spec_w%i_sub0: forall x y, [%s%i x] < [%s%i y] -> [w%i_sub x y] = 0." i c i c i i;
- pp " Proof.";
- pp " intros n m; unfold w%i_sub, w%i_sub_c." i i;
- pp " generalize (spec_sub_c w%i_spec n m); case znz_sub_c;" i;
- pp " intros x; unfold interp_carry.";
- pp " unfold to_Z; case (spec_to_Z w%i_spec x); intros; auto with zarith." i;
- pp " intros; unfold to_Z, zero, w_0; rewrite (spec_0 w0_spec); auto.";
- pp " Qed.";
- pp "";
- done;
-
- pp " Let spec_wn_sub0: forall n x y, [%sn n x] < [%sn n y] -> [subn n x y] = 0." c c;
- pp " Proof.";
- pp " intros k n m; unfold subn.";
- pp " generalize (spec_sub_c (wn_spec k) n m); case znz_sub_c;";
- pp " intros x; unfold interp_carry.";
- pp " unfold to_Z; case (spec_to_Z (wn_spec k) x); intros; auto with zarith.";
- pp " intros; unfold to_Z, w_0; rewrite (spec_0 (w0_spec)); auto.";
- pp " Qed.";
- pp "";
-
- pr " Theorem spec_sub0: forall x y, [x] < [y] -> [sub x y] = 0.";
- pa " Admitted.";
- pp " Proof.";
- pp " unfold sub.";
- pp " generalize (spec_same_level t_ (fun x y res => x < y -> [res] = 0)).";
- pp " unfold same_level; intros HH; apply HH; clear HH.";
- for i = 0 to size do
- pp " exact spec_w%i_sub0." i;
- done;
- pp " exact spec_wn_sub0.";
- pp " Qed.";
- pr "";
-
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Comparison *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition compare_%i := w%i_op.(znz_compare)." i i;
- pr " Definition comparen_%i :=" i;
- pr " compare_mn_1 w%i w%i %s compare_%i (compare_%i %s) compare_%i." i i (pz i) i i (pz i) i
- done;
- pr "";
-
- pr " Definition comparenm n m wx wy :=";
- pr " let mn := Max.max n m in";
- pr " let d := diff n m in";
- pr " let op := make_op mn in";
- pr " op.(znz_compare)";
- pr " (castm (diff_r n m) (extend_tr wx (snd d)))";
- pr " (castm (diff_l n m) (extend_tr wy (fst d))).";
- pr "";
-
- pr " Definition compare := Eval lazy beta delta [iter] in";
- pr " (iter _";
- for i = 0 to size do
- pr " compare_%i" i;
- pr " (fun n x y => CompOpp (comparen_%i (S n) y x))" i;
- pr " (fun n => comparen_%i (S n))" i;
- done;
- pr " comparenm).";
- pr "";
-
- for i = 0 to size do
- pp " Let spec_compare_%i: forall x y," i;
- pp " match compare_%i x y with" i;
- pp " Eq => [%s%i x] = [%s%i y]" c i c i;
- pp " | Lt => [%s%i x] < [%s%i y]" c i c i;
- pp " | Gt => [%s%i x] > [%s%i y]" c i c i;
- pp " end.";
- pp " Proof.";
- pp " unfold compare_%i, to_Z; exact (spec_compare w%i_spec)." i i;
- pp " Qed.";
- pp "";
-
- pp " Let spec_comparen_%i:" i;
- pp " forall (n : nat) (x : word w%i n) (y : w%i)," i i;
- pp " match comparen_%i n x y with" i;
- pp " | Eq => eval%in n x = [%s%i y]" i c i;
- pp " | Lt => eval%in n x < [%s%i y]" i c i;
- pp " | Gt => eval%in n x > [%s%i y]" i c i;
- pp " end.";
- pp " intros n x y.";
- pp " unfold comparen_%i, to_Z; rewrite spec_double_eval%in." i i;
- pp " apply spec_compare_mn_1.";
- pp " exact (spec_0 w%i_spec)." i;
- pp " intros x1; exact (spec_compare w%i_spec %s x1)." i (pz i);
- pp " exact (spec_to_Z w%i_spec)." i;
- pp " exact (spec_compare w%i_spec)." i;
- pp " exact (spec_compare w%i_spec)." i;
- pp " exact (spec_to_Z w%i_spec)." i;
- pp " Qed.";
- pp "";
- done;
-
- pp " Let spec_opp_compare: forall c (u v: Z),";
- pp " match c with Eq => u = v | Lt => u < v | Gt => u > v end ->";
- pp " match CompOpp c with Eq => v = u | Lt => v < u | Gt => v > u end.";
- pp " Proof.";
- pp " intros c u v; case c; unfold CompOpp; auto with zarith.";
- pp " Qed.";
- pp "";
-
-
- pr " Theorem spec_compare_aux: forall x y,";
- pr " match compare x y with";
- pr " Eq => [x] = [y]";
- pr " | Lt => [x] < [y]";
- pr " | Gt => [x] > [y]";
- pr " end.";
- pa " Admitted.";
- pp " Proof.";
- pp " refine (spec_iter _ (fun x y res =>";
- pp " match res with";
- pp " Eq => x = y";
- pp " | Lt => x < y";
- pp " | Gt => x > y";
- pp " end)";
- for i = 0 to size do
- pp " compare_%i" i;
- pp " (fun n x y => CompOpp (comparen_%i (S n) y x))" i;
- pp " (fun n => comparen_%i (S n)) _ _ _" i;
- done;
- pp " comparenm _).";
-
- for i = 0 to size - 1 do
- pp " exact spec_compare_%i." i;
- pp " intros n x y H;apply spec_opp_compare; apply spec_comparen_%i." i;
- pp " intros n x y H; exact (spec_comparen_%i (S n) x y)." i;
- done;
- pp " exact spec_compare_%i." size;
- pp " intros n x y;apply spec_opp_compare; apply spec_comparen_%i." size;
- pp " intros n; exact (spec_comparen_%i (S n))." size;
- pp " intros n m x y; unfold comparenm.";
- pp " rewrite <- (spec_cast_l n m x); rewrite <- (spec_cast_r n m y).";
- pp " unfold to_Z; apply (spec_compare (wn_spec (Max.max n m))).";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Multiplication *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_mul_c := w%i_op.(znz_mul_c)." i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_mul_add :=" i;
- pr " Eval lazy beta delta [w_mul_add] in";
- pr " @w_mul_add w%i %s w%i_succ w%i_add_c w%i_mul_c." i (pz i) i i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_0W := znz_0W w%i_op." i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_WW := znz_WW w%i_op." i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_mul_add_n1 :=" i;
- pr " @double_mul_add_n1 w%i %s w%i_WW w%i_0W w%i_mul_add." i (pz i) i i i
- done;
- pr "";
-
- for i = 0 to size - 1 do
- pr " Let to_Z%i n :=" i;
- pr " match n return word w%i (S n) -> t_ with" i;
- for j = 0 to size - i do
- if (i + j) == size then
- begin
- pr " | %i%s => fun x => %sn 0 x" j "%nat" c;
- pr " | %i%s => fun x => %sn 1 x" (j + 1) "%nat" c
- end
- else
- pr " | %i%s => fun x => %s%i x" j "%nat" c (i + j + 1)
- done;
- pr " | _ => fun _ => N0 w_0";
- pr " end.";
- pr "";
- done;
-
-
- for i = 0 to size - 1 do
- pp "Theorem to_Z%i_spec:" i;
- pp " forall n x, Z_of_nat n <= %i -> [to_Z%i n x] = znz_to_Z (nmake_op _ w%i_op (S n)) x." (size + 1 - i) i i;
- for j = 1 to size + 2 - i do
- pp " intros n; case n; clear n.";
- pp " unfold to_Z%i." i;
- pp " intros x H; rewrite spec_eval%in%i; auto." i j;
- done;
- pp " intros n x.";
- pp " repeat rewrite inj_S; unfold Zsucc; auto with zarith.";
- pp " Qed.";
- pp "";
- done;
-
-
- for i = 0 to size do
- pr " Definition w%i_mul n x y :=" i;
- pr " let (w,r) := w%i_mul_add_n1 (S n) x y %s in" i (pz i);
- if i == size then
- begin
- pr " if w%i_eq0 w then %sn n r" i c;
- pr " else %sn (S n) (WW (extend%i n w) r)." c i;
- end
- else
- begin
- pr " if w%i_eq0 w then to_Z%i n r" i i;
- pr " else to_Z%i (S n) (WW (extend%i n w) r)." i i;
- end;
- pr "";
- done;
-
- pr " Definition mulnm n m x y :=";
- pr " let mn := Max.max n m in";
- pr " let d := diff n m in";
- pr " let op := make_op mn in";
- pr " reduce_n (S mn) (op.(znz_mul_c)";
- pr " (castm (diff_r n m) (extend_tr x (snd d)))";
- pr " (castm (diff_l n m) (extend_tr y (fst d)))).";
- pr "";
-
- pr " Definition mul := Eval lazy beta delta [iter0] in";
- pr " (iter0 t_";
- for i = 0 to size do
- pr " (fun x y => reduce_%i (w%i_mul_c x y))" (i + 1) i;
- pr " (fun n x y => w%i_mul n y x)" i;
- pr " w%i_mul" i;
- done;
- pr " mulnm";
- pr " (fun _ => N0 w_0)";
- pr " (fun _ => N0 w_0)";
- pr " ).";
- pr "";
- for i = 0 to size do
- pp " Let spec_w%i_mul_add: forall x y z," i;
- pp " let (q,r) := w%i_mul_add x y z in" i;
- pp " znz_to_Z w%i_op q * (base (znz_digits w%i_op)) + znz_to_Z w%i_op r =" i i i;
- pp " znz_to_Z w%i_op x * znz_to_Z w%i_op y + znz_to_Z w%i_op z :=" i i i ;
- pp " (spec_mul_add w%i_spec)." i;
- pp "";
- done;
-
- for i = 0 to size do
- pp " Theorem spec_w%i_mul_add_n1: forall n x y z," i;
- pp " let (q,r) := w%i_mul_add_n1 n x y z in" i;
- pp " znz_to_Z w%i_op q * (base (znz_digits (nmake_op _ w%i_op n))) +" i i;
- pp " znz_to_Z (nmake_op _ w%i_op n) r =" i;
- pp " znz_to_Z (nmake_op _ w%i_op n) x * znz_to_Z w%i_op y +" i i;
- pp " znz_to_Z w%i_op z." i;
- pp " Proof.";
- pp " intros n x y z; unfold w%i_mul_add_n1." i;
- pp " rewrite nmake_double.";
- pp " rewrite digits_doubled.";
- pp " change (base (DoubleBase.double_digits (znz_digits w%i_op) n)) with" i;
- pp " (DoubleBase.double_wB (znz_digits w%i_op) n)." i;
- pp " apply spec_double_mul_add_n1; auto.";
- if i == 0 then pp " exact (spec_0 w%i_spec)." i;
- pp " exact (spec_WW w%i_spec)." i;
- pp " exact (spec_0W w%i_spec)." i;
- pp " exact (spec_mul_add w%i_spec)." i;
- pp " Qed.";
- pp "";
- done;
-
- pp " Lemma nmake_op_WW: forall ww ww1 n x y,";
- pp " znz_to_Z (nmake_op ww ww1 (S n)) (WW x y) =";
- pp " znz_to_Z (nmake_op ww ww1 n) x * base (znz_digits (nmake_op ww ww1 n)) +";
- pp " znz_to_Z (nmake_op ww ww1 n) y.";
- pp " auto.";
- pp " Qed.";
- pp "";
-
- for i = 0 to size do
- pp " Lemma extend%in_spec: forall n x1," i;
- pp " znz_to_Z (nmake_op _ w%i_op (S n)) (extend%i n x1) =" i i;
- pp " znz_to_Z w%i_op x1." i;
- pp " Proof.";
- pp " intros n1 x2; rewrite nmake_double.";
- pp " unfold extend%i." i;
- pp " rewrite DoubleBase.spec_extend; auto.";
- if i == 0 then
- pp " intros l; simpl; unfold w_0; rewrite (spec_0 w0_spec); ring.";
- pp " Qed.";
- pp "";
- done;
-
- pp " Lemma spec_muln:";
- pp " forall n (x: word _ (S n)) y,";
- pp " [%sn (S n) (znz_mul_c (make_op n) x y)] = [%sn n x] * [%sn n y]." c c c;
- pp " Proof.";
- pp " intros n x y; unfold to_Z.";
- pp " rewrite <- (spec_mul_c (wn_spec n)).";
- pp " rewrite make_op_S.";
- pp " case znz_mul_c; auto.";
- pp " Qed.";
- pr "";
-
- pr " Theorem spec_mul: forall x y, [mul x y] = [x] * [y].";
- pa " Admitted.";
- pp " Proof.";
- for i = 0 to size do
- pp " assert(F%i:" i;
- pp " forall n x y,";
- if i <> size then
- pp0 " Z_of_nat n <= %i -> " (size - i);
- pp " [w%i_mul n x y] = eval%in (S n) x * [%s%i y])." i i c i;
- if i == size then
- pp " intros n x y; unfold w%i_mul." i
- else
- pp " intros n x y H; unfold w%i_mul." i;
- pp " generalize (spec_w%i_mul_add_n1 (S n) x y %s)." i (pz i);
- pp " case w%i_mul_add_n1; intros x1 y1." i;
- pp " change (znz_to_Z (nmake_op _ w%i_op (S n)) x) with (eval%in (S n) x)." i i;
- pp " change (znz_to_Z w%i_op y) with ([%s%i y])." i c i;
- if i == 0 then
- pp " unfold w_0; rewrite (spec_0 w0_spec); rewrite Zplus_0_r."
- else
- pp " change (znz_to_Z w%i_op W0) with 0; rewrite Zplus_0_r." i;
- pp " intros H1; rewrite <- H1; clear H1.";
- pp " generalize (spec_w%i_eq0 x1); case w%i_eq0; intros HH." i i;
- pp " unfold to_Z in HH; rewrite HH.";
- if i == size then
- begin
- pp " rewrite spec_eval%in; unfold eval%in, nmake_op%i; auto." i i i;
- pp " rewrite spec_eval%in; unfold eval%in, nmake_op%i." i i i
- end
- else
- begin
- pp " rewrite to_Z%i_spec; auto with zarith." i;
- pp " rewrite to_Z%i_spec; try (rewrite inj_S; auto with zarith)." i
- end;
- pp " rewrite nmake_op_WW; rewrite extend%in_spec; auto." i;
- done;
- pp " refine (spec_iter0 t_ (fun x y res => [res] = x * y)";
- for i = 0 to size do
- pp " (fun x y => reduce_%i (w%i_mul_c x y))" (i + 1) i;
- pp " (fun n x y => w%i_mul n y x)" i;
- pp " w%i_mul _ _ _" i;
- done;
- pp " mulnm _";
- pp " (fun _ => N0 w_0) _";
- pp " (fun _ => N0 w_0) _";
- pp " ).";
- for i = 0 to size do
- pp " intros x y; rewrite spec_reduce_%i." (i + 1);
- pp " unfold w%i_mul_c, to_Z." i;
- pp " generalize (spec_mul_c w%i_spec x y)." i;
- pp " intros HH; rewrite <- HH; clear HH; auto.";
- if i == size then
- begin
- pp " intros n x y; rewrite F%i; auto with zarith." i;
- pp " intros n x y; rewrite F%i; auto with zarith." i;
- end
- else
- begin
- pp " intros n x y H; rewrite F%i; auto with zarith." i;
- pp " intros n x y H; rewrite F%i; auto with zarith." i;
- end;
- done;
- pp " intros n m x y; unfold mulnm.";
- pp " rewrite spec_reduce_n.";
- pp " rewrite <- (spec_cast_l n m x).";
- pp " rewrite <- (spec_cast_r n m y).";
- pp " rewrite spec_muln; rewrite spec_cast_l; rewrite spec_cast_r; auto.";
- pp " intros x; unfold to_Z, w_0; rewrite (spec_0 w0_spec); ring.";
- pp " intros x; unfold to_Z, w_0; rewrite (spec_0 w0_spec); ring.";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Square *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_square_c := w%i_op.(znz_square_c)." i i
- done;
- pr "";
-
- pr " Definition square x :=";
- pr " match x with";
- pr " | %s0 wx => reduce_1 (w0_square_c wx)" c;
- for i = 1 to size - 1 do
- pr " | %s%i wx => %s%i (w%i_square_c wx)" c i c (i+1) i
- done;
- pr " | %s%i wx => %sn 0 (w%i_square_c wx)" c size c size;
- pr " | %sn n wx =>" c;
- pr " let op := make_op n in";
- pr " %sn (S n) (op.(znz_square_c) wx)" c;
- pr " end.";
- pr "";
-
- pr " Theorem spec_square: forall x, [square x] = [x] * [x].";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold square; clear x.";
- pp " intros x; rewrite spec_reduce_1; unfold to_Z.";
- pp " exact (spec_square_c w%i_spec x)." 0;
- for i = 1 to size do
- pp " intros x; unfold to_Z.";
- pp " exact (spec_square_c w%i_spec x)." i;
- done;
- pp " intros n x; unfold to_Z.";
- pp " rewrite make_op_S.";
- pp " exact (spec_square_c (wn_spec n) x).";
- pp "Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Square root *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_sqrt := w%i_op.(znz_sqrt)." i i
- done;
- pr "";
-
- pr " Definition sqrt x :=";
- pr " match x with";
- for i = 0 to size do
- pr " | %s%i wx => reduce_%i (w%i_sqrt wx)" c i i i;
- done;
- pr " | %sn n wx =>" c;
- pr " let op := make_op n in";
- pr " reduce_n n (op.(znz_sqrt) wx)";
- pr " end.";
- pr "";
-
- pr " Theorem spec_sqrt: forall x, [sqrt x] ^ 2 <= [x] < ([sqrt x] + 1) ^ 2.";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; unfold sqrt; case x; clear x.";
- for i = 0 to size do
- pp " intros x; rewrite spec_reduce_%i; exact (spec_sqrt w%i_spec x)." i i;
- done;
- pp " intros n x; rewrite spec_reduce_n; exact (spec_sqrt (wn_spec n) x).";
- pp " Qed.";
- pr "";
-
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Division *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_div_gt := w%i_op.(znz_div_gt)." i i
- done;
- pr "";
-
- pp " Let spec_divn1 ww (ww_op: znz_op ww) (ww_spec: znz_spec ww_op) :=";
- pp " (spec_double_divn1";
- pp " ww_op.(znz_zdigits) ww_op.(znz_0)";
- pp " (znz_WW ww_op) ww_op.(znz_head0)";
- pp " ww_op.(znz_add_mul_div) ww_op.(znz_div21)";
- pp " ww_op.(znz_compare) ww_op.(znz_sub) (znz_to_Z ww_op)";
- pp " (spec_to_Z ww_spec)";
- pp " (spec_zdigits ww_spec)";
- pp " (spec_0 ww_spec) (spec_WW ww_spec) (spec_head0 ww_spec)";
- pp " (spec_add_mul_div ww_spec) (spec_div21 ww_spec)";
- pp " (CyclicAxioms.spec_compare ww_spec) (CyclicAxioms.spec_sub ww_spec)).";
- pp "";
-
- for i = 0 to size do
- pr " Definition w%i_divn1 n x y :=" i;
- pr " let (u, v) :=";
- pr " double_divn1 w%i_op.(znz_zdigits) w%i_op.(znz_0)" i i;
- pr " (znz_WW w%i_op) w%i_op.(znz_head0)" i i;
- pr " w%i_op.(znz_add_mul_div) w%i_op.(znz_div21)" i i;
- pr " w%i_op.(znz_compare) w%i_op.(znz_sub) (S n) x y in" i i;
- if i == size then
- pr " (%sn _ u, %s%i v)." c c i
- else
- pr " (to_Z%i _ u, %s%i v)." i c i;
- done;
- pr "";
-
- for i = 0 to size do
- pp " Lemma spec_get_end%i: forall n x y," i;
- pp " eval%in n x <= [%s%i y] ->" i c i;
- pp " [%s%i (DoubleBase.get_low %s n x)] = eval%in n x." c i (pz i) i;
- pp " Proof.";
- pp " intros n x y H.";
- pp " rewrite spec_double_eval%in; unfold to_Z." i;
- pp " apply DoubleBase.spec_get_low.";
- pp " exact (spec_0 w%i_spec)." i;
- pp " exact (spec_to_Z w%i_spec)." i;
- pp " apply Zle_lt_trans with [%s%i y]; auto." c i;
- pp " rewrite <- spec_double_eval%in; auto." i;
- pp " unfold to_Z; case (spec_to_Z w%i_spec y); auto." i;
- pp " Qed.";
- pp "";
- done;
-
- for i = 0 to size do
- pr " Let div_gt%i x y := let (u,v) := (w%i_div_gt x y) in (reduce_%i u, reduce_%i v)." i i i i;
- done;
- pr "";
-
-
- pr " Let div_gtnm n m wx wy :=";
- pr " let mn := Max.max n m in";
- pr " let d := diff n m in";
- pr " let op := make_op mn in";
- pr " let (q, r):= op.(znz_div_gt)";
- pr " (castm (diff_r n m) (extend_tr wx (snd d)))";
- pr " (castm (diff_l n m) (extend_tr wy (fst d))) in";
- pr " (reduce_n mn q, reduce_n mn r).";
- pr "";
-
- pr " Definition div_gt := Eval lazy beta delta [iter] in";
- pr " (iter _";
- for i = 0 to size do
- pr " div_gt%i" i;
- pr " (fun n x y => div_gt%i x (DoubleBase.get_low %s (S n) y))" i (pz i);
- pr " w%i_divn1" i;
- done;
- pr " div_gtnm).";
- pr "";
-
- pr " Theorem spec_div_gt: forall x y,";
- pr " [x] > [y] -> 0 < [y] ->";
- pr " let (q,r) := div_gt x y in";
- pr " [q] = [x] / [y] /\\ [r] = [x] mod [y].";
- pa " Admitted.";
- pp " Proof.";
- pp " assert (FO:";
- pp " forall x y, [x] > [y] -> 0 < [y] ->";
- pp " let (q,r) := div_gt x y in";
- pp " [x] = [q] * [y] + [r] /\\ 0 <= [r] < [y]).";
- pp " refine (spec_iter (t_*t_) (fun x y res => x > y -> 0 < y ->";
- pp " let (q,r) := res in";
- pp " x = [q] * y + [r] /\\ 0 <= [r] < y)";
- for i = 0 to size do
- pp " div_gt%i" i;
- pp " (fun n x y => div_gt%i x (DoubleBase.get_low %s (S n) y))" i (pz i);
- pp " w%i_divn1 _ _ _" i;
- done;
- pp " div_gtnm _).";
- for i = 0 to size do
- pp " intros x y H1 H2; unfold div_gt%i, w%i_div_gt." i i;
- pp " generalize (spec_div_gt w%i_spec x y H1 H2); case znz_div_gt." i;
- pp " intros xx yy; repeat rewrite spec_reduce_%i; auto." i;
- if i == size then
- pp " intros n x y H2 H3; unfold div_gt%i, w%i_div_gt." i i
- else
- pp " intros n x y H1 H2 H3; unfold div_gt%i, w%i_div_gt." i i;
- pp " generalize (spec_div_gt w%i_spec x" i;
- pp " (DoubleBase.get_low %s (S n) y))." (pz i);
- pp0 "";
- for j = 0 to i do
- pp0 "unfold w%i; " (i-j);
- done;
- pp "case znz_div_gt.";
- pp " intros xx yy H4; repeat rewrite spec_reduce_%i." i;
- pp " generalize (spec_get_end%i (S n) y x); unfold to_Z; intros H5." i;
- pp " unfold to_Z in H2; rewrite H5 in H4; auto with zarith.";
- if i == size then
- pp " intros n x y H2 H3."
- else
- pp " intros n x y H1 H2 H3.";
- pp " generalize";
- pp " (spec_divn1 w%i w%i_op w%i_spec (S n) x y H3)." i i i;
- pp0 " unfold w%i_divn1; " i;
- for j = 0 to i do
- pp0 "unfold w%i; " (i-j);
- done;
- pp "case double_divn1.";
- pp " intros xx yy H4.";
- if i == size then
- begin
- pp " repeat rewrite <- spec_double_eval%in in H4; auto." i;
- pp " rewrite spec_eval%in; auto." i;
- end
- else
- begin
- pp " rewrite to_Z%i_spec; auto with zarith." i;
- pp " repeat rewrite <- spec_double_eval%in in H4; auto." i;
- end;
- done;
- pp " intros n m x y H1 H2; unfold div_gtnm.";
- pp " generalize (spec_div_gt (wn_spec (Max.max n m))";
- pp " (castm (diff_r n m)";
- pp " (extend_tr x (snd (diff n m))))";
- pp " (castm (diff_l n m)";
- pp " (extend_tr y (fst (diff n m))))).";
- pp " case znz_div_gt.";
- pp " intros xx yy HH.";
- pp " repeat rewrite spec_reduce_n.";
- pp " rewrite <- (spec_cast_l n m x).";
- pp " rewrite <- (spec_cast_r n m y).";
- pp " unfold to_Z; apply HH.";
- pp " rewrite <- (spec_cast_l n m x) in H1; auto.";
- pp " rewrite <- (spec_cast_r n m y) in H1; auto.";
- pp " rewrite <- (spec_cast_r n m y) in H2; auto.";
- pp " intros x y H1 H2; generalize (FO x y H1 H2); case div_gt.";
- pp " intros q r (H3, H4); split.";
- pp " apply (Zdiv_unique [x] [y] [q] [r]); auto.";
- pp " rewrite Zmult_comm; auto.";
- pp " apply (Zmod_unique [x] [y] [q] [r]); auto.";
- pp " rewrite Zmult_comm; auto.";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Modulo *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_mod_gt := w%i_op.(znz_mod_gt)." i i
- done;
- pr "";
-
- for i = 0 to size do
- pr " Definition w%i_modn1 :=" i;
- pr " double_modn1 w%i_op.(znz_zdigits) w%i_op.(znz_0)" i i;
- pr " w%i_op.(znz_head0) w%i_op.(znz_add_mul_div) w%i_op.(znz_div21)" i i i;
- pr " w%i_op.(znz_compare) w%i_op.(znz_sub)." i i;
- done;
- pr "";
-
- pr " Let mod_gtnm n m wx wy :=";
- pr " let mn := Max.max n m in";
- pr " let d := diff n m in";
- pr " let op := make_op mn in";
- pr " reduce_n mn (op.(znz_mod_gt)";
- pr " (castm (diff_r n m) (extend_tr wx (snd d)))";
- pr " (castm (diff_l n m) (extend_tr wy (fst d)))).";
- pr "";
-
- pr " Definition mod_gt := Eval lazy beta delta[iter] in";
- pr " (iter _";
- for i = 0 to size do
- pr " (fun x y => reduce_%i (w%i_mod_gt x y))" i i;
- pr " (fun n x y => reduce_%i (w%i_mod_gt x (DoubleBase.get_low %s (S n) y)))" i i (pz i);
- pr " (fun n x y => reduce_%i (w%i_modn1 (S n) x y))" i i;
- done;
- pr " mod_gtnm).";
- pr "";
-
- pp " Let spec_modn1 ww (ww_op: znz_op ww) (ww_spec: znz_spec ww_op) :=";
- pp " (spec_double_modn1";
- pp " ww_op.(znz_zdigits) ww_op.(znz_0)";
- pp " (znz_WW ww_op) ww_op.(znz_head0)";
- pp " ww_op.(znz_add_mul_div) ww_op.(znz_div21)";
- pp " ww_op.(znz_compare) ww_op.(znz_sub) (znz_to_Z ww_op)";
- pp " (spec_to_Z ww_spec)";
- pp " (spec_zdigits ww_spec)";
- pp " (spec_0 ww_spec) (spec_WW ww_spec) (spec_head0 ww_spec)";
- pp " (spec_add_mul_div ww_spec) (spec_div21 ww_spec)";
- pp " (CyclicAxioms.spec_compare ww_spec) (CyclicAxioms.spec_sub ww_spec)).";
- pp "";
-
- pr " Theorem spec_mod_gt:";
- pr " forall x y, [x] > [y] -> 0 < [y] -> [mod_gt x y] = [x] mod [y].";
- pa " Admitted.";
- pp " Proof.";
- pp " refine (spec_iter _ (fun x y res => x > y -> 0 < y ->";
- pp " [res] = x mod y)";
- for i = 0 to size do
- pp " (fun x y => reduce_%i (w%i_mod_gt x y))" i i;
- pp " (fun n x y => reduce_%i (w%i_mod_gt x (DoubleBase.get_low %s (S n) y)))" i i (pz i);
- pp " (fun n x y => reduce_%i (w%i_modn1 (S n) x y)) _ _ _" i i;
- done;
- pp " mod_gtnm _).";
- for i = 0 to size do
- pp " intros x y H1 H2; rewrite spec_reduce_%i." i;
- pp " exact (spec_mod_gt w%i_spec x y H1 H2)." i;
- if i == size then
- pp " intros n x y H2 H3; rewrite spec_reduce_%i." i
- else
- pp " intros n x y H1 H2 H3; rewrite spec_reduce_%i." i;
- pp " unfold w%i_mod_gt." i;
- pp " rewrite <- (spec_get_end%i (S n) y x); auto with zarith." i;
- pp " unfold to_Z; apply (spec_mod_gt w%i_spec); auto." i;
- pp " rewrite <- (spec_get_end%i (S n) y x) in H2; auto with zarith." i;
- pp " rewrite <- (spec_get_end%i (S n) y x) in H3; auto with zarith." i;
- if i == size then
- pp " intros n x y H2 H3; rewrite spec_reduce_%i." i
- else
- pp " intros n x y H1 H2 H3; rewrite spec_reduce_%i." i;
- pp " unfold w%i_modn1, to_Z; rewrite spec_double_eval%in." i i;
- pp " apply (spec_modn1 _ _ w%i_spec); auto." i;
- done;
- pp " intros n m x y H1 H2; unfold mod_gtnm.";
- pp " repeat rewrite spec_reduce_n.";
- pp " rewrite <- (spec_cast_l n m x).";
- pp " rewrite <- (spec_cast_r n m y).";
- pp " unfold to_Z; apply (spec_mod_gt (wn_spec (Max.max n m))).";
- pp " rewrite <- (spec_cast_l n m x) in H1; auto.";
- pp " rewrite <- (spec_cast_r n m y) in H1; auto.";
- pp " rewrite <- (spec_cast_r n m y) in H2; auto.";
- pp " Qed.";
- pr "";
-
- pr " (** digits: a measure for gcd *)";
- pr "";
-
- pr " Definition digits x :=";
- pr " match x with";
- for i = 0 to size do
- pr " | %s%i _ => w%i_op.(znz_digits)" c i i;
- done;
- pr " | %sn n _ => (make_op n).(znz_digits)" c;
- pr " end.";
- pr "";
-
- pr " Theorem spec_digits: forall x, 0 <= [x] < 2 ^ Zpos (digits x).";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; clear x.";
- for i = 0 to size do
- pp " intros x; unfold to_Z, digits;";
- pp " generalize (spec_to_Z w%i_spec x); unfold base; intros H; exact H." i;
- done;
- pp " intros n x; unfold to_Z, digits;";
- pp " generalize (spec_to_Z (wn_spec n) x); unfold base; intros H; exact H.";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Conversion *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- pr " Definition pheight p :=";
- pr " Peano.pred (nat_of_P (get_height w0_op.(znz_digits) (plength p))).";
- pr "";
-
- pr " Theorem pheight_correct: forall p,";
- pr " Zpos p < 2 ^ (Zpos (znz_digits w0_op) * 2 ^ (Z_of_nat (pheight p))).";
- pr " Proof.";
- pr " intros p; unfold pheight.";
- pr " assert (F1: forall x, Z_of_nat (Peano.pred (nat_of_P x)) = Zpos x - 1).";
- pr " intros x.";
- pr " assert (Zsucc (Z_of_nat (Peano.pred (nat_of_P x))) = Zpos x); auto with zarith.";
- pr " rewrite <- inj_S.";
- pr " rewrite <- (fun x => S_pred x 0); auto with zarith.";
- pr " rewrite Zpos_eq_Z_of_nat_o_nat_of_P; auto.";
- pr " apply lt_le_trans with 1%snat; auto with zarith." "%";
- pr " exact (le_Pmult_nat x 1).";
- pr " rewrite F1; clear F1.";
- pr " assert (F2:= (get_height_correct (znz_digits w0_op) (plength p))).";
- pr " apply Zlt_le_trans with (Zpos (Psucc p)).";
- pr " rewrite Zpos_succ_morphism; auto with zarith.";
- pr " apply Zle_trans with (1 := plength_pred_correct (Psucc p)).";
- pr " rewrite Ppred_succ.";
- pr " apply Zpower_le_monotone; auto with zarith.";
- pr " Qed.";
- pr "";
-
- pr " Definition of_pos x :=";
- pr " let h := pheight x in";
- pr " match h with";
- for i = 0 to size do
- pr " | %i%snat => reduce_%i (snd (w%i_op.(znz_of_pos) x))" i "%" i i;
- done;
- pr " | _ =>";
- pr " let n := minus h %i in" (size + 1);
- pr " reduce_n n (snd ((make_op n).(znz_of_pos) x))";
- pr " end.";
- pr "";
-
- pr " Theorem spec_of_pos: forall x,";
- pr " [of_pos x] = Zpos x.";
- pa " Admitted.";
- pp " Proof.";
- pp " assert (F := spec_more_than_1_digit w0_spec).";
- pp " intros x; unfold of_pos; case_eq (pheight x).";
- for i = 0 to size do
- if i <> 0 then
- pp " intros n; case n; clear n.";
- pp " intros H1; rewrite spec_reduce_%i; unfold to_Z." i;
- pp " apply (znz_of_pos_correct w%i_spec)." i;
- pp " apply Zlt_le_trans with (1 := pheight_correct x).";
- pp " rewrite H1; simpl Z_of_nat; change (2^%i) with (%s)." i (gen2 i);
- pp " unfold base.";
- pp " apply Zpower_le_monotone; split; auto with zarith.";
- if i <> 0 then
- begin
- pp " rewrite Zmult_comm; repeat rewrite <- Zmult_assoc.";
- pp " repeat rewrite <- Zpos_xO.";
- pp " refine (Zle_refl _).";
- end;
- done;
- pp " intros n.";
- pp " intros H1; rewrite spec_reduce_n; unfold to_Z.";
- pp " simpl minus; rewrite <- minus_n_O.";
- pp " apply (znz_of_pos_correct (wn_spec n)).";
- pp " apply Zlt_le_trans with (1 := pheight_correct x).";
- pp " unfold base.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " split; auto with zarith.";
- pp " rewrite H1.";
- pp " elim n; clear n H1.";
- pp " simpl Z_of_nat; change (2^%i) with (%s)." (size + 1) (gen2 (size + 1));
- pp " rewrite Zmult_comm; repeat rewrite <- Zmult_assoc.";
- pp " repeat rewrite <- Zpos_xO.";
- pp " refine (Zle_refl _).";
- pp " intros n Hrec.";
- pp " rewrite make_op_S.";
- pp " change (@znz_digits (word _ (S (S n))) (mk_zn2z_op_karatsuba (make_op n))) with";
- pp " (xO (znz_digits (make_op n))).";
- pp " rewrite (fun x y => (Zpos_xO (@znz_digits x y))).";
- pp " rewrite inj_S; unfold Zsucc.";
- pp " rewrite Zplus_comm; rewrite Zpower_exp; auto with zarith.";
- pp " rewrite Zpower_1_r.";
- pp " assert (tmp: forall x y z, x * (y * z) = y * (x * z));";
- pp " [intros; ring | rewrite tmp; clear tmp].";
- pp " apply Zmult_le_compat_l; auto with zarith.";
- pp " Qed.";
- pr "";
-
- pr " (***************************************************************)";
- pr " (* *)";
- pr " (** * Shift *)";
- pr " (* *)";
- pr " (***************************************************************)";
- pr "";
-
- (* Head0 *)
- pr " Definition head0 w := match w with";
- for i = 0 to size do
- pr " | %s%i w=> reduce_%i (w%i_op.(znz_head0) w)" c i i i;
- done;
- pr " | %sn n w=> reduce_n n ((make_op n).(znz_head0) w)" c;
- pr " end.";
- pr "";
-
- pr " Theorem spec_head00: forall x, [x] = 0 ->[head0 x] = Zpos (digits x).";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold head0; clear x.";
- for i = 0 to size do
- pp " intros x; rewrite spec_reduce_%i; exact (spec_head00 w%i_spec x)." i i;
- done;
- pp " intros n x; rewrite spec_reduce_n; exact (spec_head00 (wn_spec n) x).";
- pp " Qed.";
- pr "";
-
- pr " Theorem spec_head0: forall x, 0 < [x] ->";
- pr " 2 ^ (Zpos (digits x) - 1) <= 2 ^ [head0 x] * [x] < 2 ^ Zpos (digits x).";
- pa " Admitted.";
- pp " Proof.";
- pp " assert (F0: forall x, (x - 1) + 1 = x).";
- pp " intros; ring.";
- pp " intros x; case x; unfold digits, head0; clear x.";
- for i = 0 to size do
- pp " intros x Hx; rewrite spec_reduce_%i." i;
- pp " assert (F1:= spec_more_than_1_digit w%i_spec)." i;
- pp " generalize (spec_head0 w%i_spec x Hx)." i;
- pp " unfold base.";
- pp " pattern (Zpos (znz_digits w%i_op)) at 1;" i;
- pp " rewrite <- (fun x => (F0 (Zpos x))).";
- pp " rewrite Zpower_exp; auto with zarith.";
- pp " rewrite Zpower_1_r; rewrite Z_div_mult; auto with zarith.";
- done;
- pp " intros n x Hx; rewrite spec_reduce_n.";
- pp " assert (F1:= spec_more_than_1_digit (wn_spec n)).";
- pp " generalize (spec_head0 (wn_spec n) x Hx).";
- pp " unfold base.";
- pp " pattern (Zpos (znz_digits (make_op n))) at 1;";
- pp " rewrite <- (fun x => (F0 (Zpos x))).";
- pp " rewrite Zpower_exp; auto with zarith.";
- pp " rewrite Zpower_1_r; rewrite Z_div_mult; auto with zarith.";
- pp " Qed.";
- pr "";
-
-
- (* Tail0 *)
- pr " Definition tail0 w := match w with";
- for i = 0 to size do
- pr " | %s%i w=> reduce_%i (w%i_op.(znz_tail0) w)" c i i i;
- done;
- pr " | %sn n w=> reduce_n n ((make_op n).(znz_tail0) w)" c;
- pr " end.";
- pr "";
-
-
- pr " Theorem spec_tail00: forall x, [x] = 0 ->[tail0 x] = Zpos (digits x).";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold tail0; clear x.";
- for i = 0 to size do
- pp " intros x; rewrite spec_reduce_%i; exact (spec_tail00 w%i_spec x)." i i;
- done;
- pp " intros n x; rewrite spec_reduce_n; exact (spec_tail00 (wn_spec n) x).";
- pp " Qed.";
- pr "";
-
-
- pr " Theorem spec_tail0: forall x,";
- pr " 0 < [x] -> exists y, 0 <= y /\\ [x] = (2 * y + 1) * 2 ^ [tail0 x].";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; clear x; unfold tail0.";
- for i = 0 to size do
- pp " intros x Hx; rewrite spec_reduce_%i; exact (spec_tail0 w%i_spec x Hx)." i i;
- done;
- pp " intros n x Hx; rewrite spec_reduce_n; exact (spec_tail0 (wn_spec n) x Hx).";
- pp " Qed.";
- pr "";
-
-
- (* Number of digits *)
- pr " Definition %sdigits x :=" c;
- pr " match x with";
- pr " | %s0 _ => %s0 w0_op.(znz_zdigits)" c c;
- for i = 1 to size do
- pr " | %s%i _ => reduce_%i w%i_op.(znz_zdigits)" c i i i;
- done;
- pr " | %sn n _ => reduce_n n (make_op n).(znz_zdigits)" c;
- pr " end.";
- pr "";
-
- pr " Theorem spec_Ndigits: forall x, [Ndigits x] = Zpos (digits x).";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; clear x; unfold Ndigits, digits.";
- for i = 0 to size do
- pp " intros _; try rewrite spec_reduce_%i; exact (spec_zdigits w%i_spec)." i i;
- done;
- pp " intros n _; try rewrite spec_reduce_n; exact (spec_zdigits (wn_spec n)).";
- pp " Qed.";
- pr "";
-
-
- (* Shiftr *)
- for i = 0 to size do
- pr " Definition unsafe_shiftr%i n x := w%i_op.(znz_add_mul_div) (w%i_op.(znz_sub) w%i_op.(znz_zdigits) n) w%i_op.(znz_0) x." i i i i i;
- done;
- pr " Definition unsafe_shiftrn n p x := (make_op n).(znz_add_mul_div) ((make_op n).(znz_sub) (make_op n).(znz_zdigits) p) (make_op n).(znz_0) x.";
- pr "";
-
- pr " Definition unsafe_shiftr := Eval lazy beta delta [same_level] in";
- pr " same_level _ (fun n x => %s0 (unsafe_shiftr0 n x))" c;
- for i = 1 to size do
- pr " (fun n x => reduce_%i (unsafe_shiftr%i n x))" i i;
- done;
- pr " (fun n p x => reduce_n n (unsafe_shiftrn n p x)).";
- pr "";
-
-
- pr " Theorem spec_unsafe_shiftr: forall n x,";
- pr " [n] <= [Ndigits x] -> [unsafe_shiftr n x] = [x] / 2 ^ [n].";
- pa " Admitted.";
- pp " Proof.";
- pp " assert (F0: forall x y, x - (x - y) = y).";
- pp " intros; ring.";
- pp " assert (F2: forall x y z, 0 <= x -> 0 <= y -> x < z -> 0 <= x / 2 ^ y < z).";
- pp " intros x y z HH HH1 HH2.";
- pp " split; auto with zarith.";
- pp " apply Zle_lt_trans with (2 := HH2); auto with zarith.";
- pp " apply Zdiv_le_upper_bound; auto with zarith.";
- pp " pattern x at 1; replace x with (x * 2 ^ 0); auto with zarith.";
- pp " apply Zmult_le_compat_l; auto.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " rewrite Zpower_0_r; ring.";
- pp " assert (F3: forall x y, 0 <= y -> y <= x -> 0 <= x - y < 2 ^ x).";
- pp " intros xx y HH HH1.";
- pp " split; auto with zarith.";
- pp " apply Zle_lt_trans with xx; auto with zarith.";
- pp " apply Zpower2_lt_lin; auto with zarith.";
- pp " assert (F4: forall ww ww1 ww2";
- pp " (ww_op: znz_op ww) (ww1_op: znz_op ww1) (ww2_op: znz_op ww2)";
- pp " xx yy xx1 yy1,";
- pp " znz_to_Z ww2_op yy <= znz_to_Z ww1_op (znz_zdigits ww1_op) ->";
- pp " znz_to_Z ww1_op (znz_zdigits ww1_op) <= znz_to_Z ww_op (znz_zdigits ww_op) ->";
- pp " znz_spec ww_op -> znz_spec ww1_op -> znz_spec ww2_op ->";
- pp " znz_to_Z ww_op xx1 = znz_to_Z ww1_op xx ->";
- pp " znz_to_Z ww_op yy1 = znz_to_Z ww2_op yy ->";
- pp " znz_to_Z ww_op";
- pp " (znz_add_mul_div ww_op (znz_sub ww_op (znz_zdigits ww_op) yy1)";
- pp " (znz_0 ww_op) xx1) = znz_to_Z ww1_op xx / 2 ^ znz_to_Z ww2_op yy).";
- pp " intros ww ww1 ww2 ww_op ww1_op ww2_op xx yy xx1 yy1 Hl Hl1 Hw Hw1 Hw2 Hx Hy.";
- pp " case (spec_to_Z Hw xx1); auto with zarith; intros HH1 HH2.";
- pp " case (spec_to_Z Hw yy1); auto with zarith; intros HH3 HH4.";
- pp " rewrite <- Hx.";
- pp " rewrite <- Hy.";
- pp " generalize (spec_add_mul_div Hw";
- pp " (znz_0 ww_op) xx1";
- pp " (znz_sub ww_op (znz_zdigits ww_op)";
- pp " yy1)";
- pp " ).";
- pp " rewrite (spec_0 Hw).";
- pp " rewrite Zmult_0_l; rewrite Zplus_0_l.";
- pp " rewrite (CyclicAxioms.spec_sub Hw).";
- pp " rewrite Zmod_small; auto with zarith.";
- pp " rewrite (spec_zdigits Hw).";
- pp " rewrite F0.";
- pp " rewrite Zmod_small; auto with zarith.";
- pp " unfold base; rewrite (spec_zdigits Hw) in Hl1 |- *;";
- pp " auto with zarith.";
- pp " assert (F5: forall n m, (n <= m)%snat ->" "%";
- pp " Zpos (znz_digits (make_op n)) <= Zpos (znz_digits (make_op m))).";
- pp " intros n m HH; elim HH; clear m HH; auto with zarith.";
- pp " intros m HH Hrec; apply Zle_trans with (1 := Hrec).";
- pp " rewrite make_op_S.";
- pp " match goal with |- Zpos ?Y <= ?X => change X with (Zpos (xO Y)) end.";
- pp " rewrite Zpos_xO.";
- pp " assert (0 <= Zpos (znz_digits (make_op n))); auto with zarith.";
- pp " assert (F6: forall n, Zpos (znz_digits w%i_op) <= Zpos (znz_digits (make_op n)))." size;
- pp " intros n ; apply Zle_trans with (Zpos (znz_digits (make_op 0))).";
- pp " change (znz_digits (make_op 0)) with (xO (znz_digits w%i_op))." size;
- pp " rewrite Zpos_xO.";
- pp " assert (0 <= Zpos (znz_digits w%i_op)); auto with zarith." size;
- pp " apply F5; auto with arith.";
- pp " intros x; case x; clear x; unfold unsafe_shiftr, same_level.";
- for i = 0 to size do
- pp " intros x y; case y; clear y.";
- for j = 0 to i - 1 do
- pp " intros y; unfold unsafe_shiftr%i, Ndigits." i;
- pp " repeat rewrite spec_reduce_%i; repeat rewrite spec_reduce_%i; unfold to_Z; intros H1." i j;
- pp " apply F4 with (3:=w%i_spec)(4:=w%i_spec)(5:=w%i_spec); auto with zarith." i j i;
- pp " rewrite (spec_zdigits w%i_spec)." i;
- pp " rewrite (spec_zdigits w%i_spec)." j;
- pp " change (znz_digits w%i_op) with %s." i (genxO (i - j) (" (znz_digits w"^(string_of_int j)^"_op)"));
- pp " repeat rewrite (fun x => Zpos_xO (xO x)).";
- pp " repeat rewrite (fun x y => Zpos_xO (@znz_digits x y)).";
- pp " assert (0 <= Zpos (znz_digits w%i_op)); auto with zarith." j;
- pp " try (apply sym_equal; exact (spec_extend%in%i y))." j i;
-
- done;
- pp " intros y; unfold unsafe_shiftr%i, Ndigits." i;
- pp " repeat rewrite spec_reduce_%i; unfold to_Z; intros H1." i;
- pp " apply F4 with (3:=w%i_spec)(4:=w%i_spec)(5:=w%i_spec); auto with zarith." i i i;
- for j = i + 1 to size do
- pp " intros y; unfold unsafe_shiftr%i, Ndigits." j;
- pp " repeat rewrite spec_reduce_%i; repeat rewrite spec_reduce_%i; unfold to_Z; intros H1." i j;
- pp " apply F4 with (3:=w%i_spec)(4:=w%i_spec)(5:=w%i_spec); auto with zarith." j j i;
- pp " try (apply sym_equal; exact (spec_extend%in%i x))." i j;
- done;
- if i == size then
- begin
- pp " intros m y; unfold unsafe_shiftrn, Ndigits.";
- pp " repeat rewrite spec_reduce_n; unfold to_Z; intros H1.";
- pp " apply F4 with (3:=(wn_spec m))(4:=wn_spec m)(5:=w%i_spec); auto with zarith." size;
- pp " try (apply sym_equal; exact (spec_extend%in m x))." size;
- end
- else
- begin
- pp " intros m y; unfold unsafe_shiftrn, Ndigits.";
- pp " repeat rewrite spec_reduce_n; unfold to_Z; intros H1.";
- pp " apply F4 with (3:=(wn_spec m))(4:=wn_spec m)(5:=w%i_spec); auto with zarith." i;
- pp " change ([Nn m (extend%i m (extend%i %i x))] = [N%i x])." size i (size - i - 1) i;
- pp " rewrite <- (spec_extend%in m); rewrite <- spec_extend%in%i; auto." size i size;
- end
- done;
- pp " intros n x y; case y; clear y;";
- pp " intros y; unfold unsafe_shiftrn, Ndigits; try rewrite spec_reduce_n.";
- for i = 0 to size do
- pp " try rewrite spec_reduce_%i; unfold to_Z; intros H1." i;
- pp " apply F4 with (3:=(wn_spec n))(4:=w%i_spec)(5:=wn_spec n); auto with zarith." i;
- pp " rewrite (spec_zdigits w%i_spec)." i;
- pp " rewrite (spec_zdigits (wn_spec n)).";
- pp " apply Zle_trans with (2 := F6 n).";
- pp " change (znz_digits w%i_op) with %s." size (genxO (size - i) ("(znz_digits w" ^ (string_of_int i) ^ "_op)"));
- pp " repeat rewrite (fun x => Zpos_xO (xO x)).";
- pp " repeat rewrite (fun x y => Zpos_xO (@znz_digits x y)).";
- pp " assert (H: 0 <= Zpos (znz_digits w%i_op)); auto with zarith." i;
- if i == size then
- pp " change ([Nn n (extend%i n y)] = [N%i y])." size i
- else
- pp " change ([Nn n (extend%i n (extend%i %i y))] = [N%i y])." size i (size - i - 1) i;
- pp " rewrite <- (spec_extend%in n); auto." size;
- if i <> size then
- pp " try (rewrite <- spec_extend%in%i; auto)." i size;
- done;
- pp " generalize y; clear y; intros m y.";
- pp " rewrite spec_reduce_n; unfold to_Z; intros H1.";
- pp " apply F4 with (3:=(wn_spec (Max.max n m)))(4:=wn_spec m)(5:=wn_spec n); auto with zarith.";
- pp " rewrite (spec_zdigits (wn_spec m)).";
- pp " rewrite (spec_zdigits (wn_spec (Max.max n m))).";
- pp " apply F5; auto with arith.";
- pp " exact (spec_cast_r n m y).";
- pp " exact (spec_cast_l n m x).";
- pp " Qed.";
- pr "";
-
- (* Unsafe_Shiftl *)
- for i = 0 to size do
- pr " Definition unsafe_shiftl%i n x := w%i_op.(znz_add_mul_div) n x w%i_op.(znz_0)." i i i
- done;
- pr " Definition unsafe_shiftln n p x := (make_op n).(znz_add_mul_div) p x (make_op n).(znz_0).";
- pr " Definition unsafe_shiftl := Eval lazy beta delta [same_level] in";
- pr " same_level _ (fun n x => %s0 (unsafe_shiftl0 n x))" c;
- for i = 1 to size do
- pr " (fun n x => reduce_%i (unsafe_shiftl%i n x))" i i;
- done;
- pr " (fun n p x => reduce_n n (unsafe_shiftln n p x)).";
- pr "";
- pr "";
-
-
- pr " Theorem spec_unsafe_shiftl: forall n x,";
- pr " [n] <= [head0 x] -> [unsafe_shiftl n x] = [x] * 2 ^ [n].";
- pa " Admitted.";
- pp " Proof.";
- pp " assert (F0: forall x y, x - (x - y) = y).";
- pp " intros; ring.";
- pp " assert (F2: forall x y z, 0 <= x -> 0 <= y -> x < z -> 0 <= x / 2 ^ y < z).";
- pp " intros x y z HH HH1 HH2.";
- pp " split; auto with zarith.";
- pp " apply Zle_lt_trans with (2 := HH2); auto with zarith.";
- pp " apply Zdiv_le_upper_bound; auto with zarith.";
- pp " pattern x at 1; replace x with (x * 2 ^ 0); auto with zarith.";
- pp " apply Zmult_le_compat_l; auto.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " rewrite Zpower_0_r; ring.";
- pp " assert (F3: forall x y, 0 <= y -> y <= x -> 0 <= x - y < 2 ^ x).";
- pp " intros xx y HH HH1.";
- pp " split; auto with zarith.";
- pp " apply Zle_lt_trans with xx; auto with zarith.";
- pp " apply Zpower2_lt_lin; auto with zarith.";
- pp " assert (F4: forall ww ww1 ww2";
- pp " (ww_op: znz_op ww) (ww1_op: znz_op ww1) (ww2_op: znz_op ww2)";
- pp " xx yy xx1 yy1,";
- pp " znz_to_Z ww2_op yy <= znz_to_Z ww1_op (znz_head0 ww1_op xx) ->";
- pp " znz_to_Z ww1_op (znz_zdigits ww1_op) <= znz_to_Z ww_op (znz_zdigits ww_op) ->";
- pp " znz_spec ww_op -> znz_spec ww1_op -> znz_spec ww2_op ->";
- pp " znz_to_Z ww_op xx1 = znz_to_Z ww1_op xx ->";
- pp " znz_to_Z ww_op yy1 = znz_to_Z ww2_op yy ->";
- pp " znz_to_Z ww_op";
- pp " (znz_add_mul_div ww_op yy1";
- pp " xx1 (znz_0 ww_op)) = znz_to_Z ww1_op xx * 2 ^ znz_to_Z ww2_op yy).";
- pp " intros ww ww1 ww2 ww_op ww1_op ww2_op xx yy xx1 yy1 Hl Hl1 Hw Hw1 Hw2 Hx Hy.";
- pp " case (spec_to_Z Hw xx1); auto with zarith; intros HH1 HH2.";
- pp " case (spec_to_Z Hw yy1); auto with zarith; intros HH3 HH4.";
- pp " rewrite <- Hx.";
- pp " rewrite <- Hy.";
- pp " generalize (spec_add_mul_div Hw xx1 (znz_0 ww_op) yy1).";
- pp " rewrite (spec_0 Hw).";
- pp " assert (F1: znz_to_Z ww1_op (znz_head0 ww1_op xx) <= Zpos (znz_digits ww1_op)).";
- pp " case (Zle_lt_or_eq _ _ HH1); intros HH5.";
- pp " apply Zlt_le_weak.";
- pp " case (CyclicAxioms.spec_head0 Hw1 xx).";
- pp " rewrite <- Hx; auto.";
- pp " intros _ Hu; unfold base in Hu.";
- pp " case (Zle_or_lt (Zpos (znz_digits ww1_op))";
- pp " (znz_to_Z ww1_op (znz_head0 ww1_op xx))); auto; intros H1.";
- pp " absurd (2 ^ (Zpos (znz_digits ww1_op)) <= 2 ^ (znz_to_Z ww1_op (znz_head0 ww1_op xx))).";
- pp " apply Zlt_not_le.";
- pp " case (spec_to_Z Hw1 xx); intros HHx3 HHx4.";
- pp " rewrite <- (Zmult_1_r (2 ^ znz_to_Z ww1_op (znz_head0 ww1_op xx))).";
- pp " apply Zle_lt_trans with (2 := Hu).";
- pp " apply Zmult_le_compat_l; auto with zarith.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " rewrite (CyclicAxioms.spec_head00 Hw1 xx); auto with zarith.";
- pp " rewrite Zdiv_0_l; auto with zarith.";
- pp " rewrite Zplus_0_r.";
- pp " case (Zle_lt_or_eq _ _ HH1); intros HH5.";
- pp " rewrite Zmod_small; auto with zarith.";
- pp " intros HH; apply HH.";
- pp " rewrite Hy; apply Zle_trans with (1:= Hl).";
- pp " rewrite <- (spec_zdigits Hw).";
- pp " apply Zle_trans with (2 := Hl1); auto.";
- pp " rewrite (spec_zdigits Hw1); auto with zarith.";
- pp " split; auto with zarith .";
- pp " apply Zlt_le_trans with (base (znz_digits ww1_op)).";
- pp " rewrite Hx.";
- pp " case (CyclicAxioms.spec_head0 Hw1 xx); auto.";
- pp " rewrite <- Hx; auto.";
- pp " intros _ Hu; rewrite Zmult_comm in Hu.";
- pp " apply Zle_lt_trans with (2 := Hu).";
- pp " apply Zmult_le_compat_l; auto with zarith.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " unfold base; apply Zpower_le_monotone; auto with zarith.";
- pp " split; auto with zarith.";
- pp " rewrite <- (spec_zdigits Hw); auto with zarith.";
- pp " rewrite <- (spec_zdigits Hw1); auto with zarith.";
- pp " rewrite <- HH5.";
- pp " rewrite Zmult_0_l.";
- pp " rewrite Zmod_small; auto with zarith.";
- pp " intros HH; apply HH.";
- pp " rewrite Hy; apply Zle_trans with (1 := Hl).";
- pp " rewrite (CyclicAxioms.spec_head00 Hw1 xx); auto with zarith.";
- pp " rewrite <- (spec_zdigits Hw); auto with zarith.";
- pp " rewrite <- (spec_zdigits Hw1); auto with zarith.";
- pp " assert (F5: forall n m, (n <= m)%snat ->" "%";
- pp " Zpos (znz_digits (make_op n)) <= Zpos (znz_digits (make_op m))).";
- pp " intros n m HH; elim HH; clear m HH; auto with zarith.";
- pp " intros m HH Hrec; apply Zle_trans with (1 := Hrec).";
- pp " rewrite make_op_S.";
- pp " match goal with |- Zpos ?Y <= ?X => change X with (Zpos (xO Y)) end.";
- pp " rewrite Zpos_xO.";
- pp " assert (0 <= Zpos (znz_digits (make_op n))); auto with zarith.";
- pp " assert (F6: forall n, Zpos (znz_digits w%i_op) <= Zpos (znz_digits (make_op n)))." size;
- pp " intros n ; apply Zle_trans with (Zpos (znz_digits (make_op 0))).";
- pp " change (znz_digits (make_op 0)) with (xO (znz_digits w%i_op))." size;
- pp " rewrite Zpos_xO.";
- pp " assert (0 <= Zpos (znz_digits w%i_op)); auto with zarith." size;
- pp " apply F5; auto with arith.";
- pp " intros x; case x; clear x; unfold unsafe_shiftl, same_level.";
- for i = 0 to size do
- pp " intros x y; case y; clear y.";
- for j = 0 to i - 1 do
- pp " intros y; unfold unsafe_shiftl%i, head0." i;
- pp " repeat rewrite spec_reduce_%i; repeat rewrite spec_reduce_%i; unfold to_Z; intros H1." i j;
- pp " apply F4 with (3:=w%i_spec)(4:=w%i_spec)(5:=w%i_spec); auto with zarith." i j i;
- pp " rewrite (spec_zdigits w%i_spec)." i;
- pp " rewrite (spec_zdigits w%i_spec)." j;
- pp " change (znz_digits w%i_op) with %s." i (genxO (i - j) (" (znz_digits w"^(string_of_int j)^"_op)"));
- pp " repeat rewrite (fun x => Zpos_xO (xO x)).";
- pp " repeat rewrite (fun x y => Zpos_xO (@znz_digits x y)).";
- pp " assert (0 <= Zpos (znz_digits w%i_op)); auto with zarith." j;
- pp " try (apply sym_equal; exact (spec_extend%in%i y))." j i;
- done;
- pp " intros y; unfold unsafe_shiftl%i, head0." i;
- pp " repeat rewrite spec_reduce_%i; unfold to_Z; intros H1." i;
- pp " apply F4 with (3:=w%i_spec)(4:=w%i_spec)(5:=w%i_spec); auto with zarith." i i i;
- for j = i + 1 to size do
- pp " intros y; unfold unsafe_shiftl%i, head0." j;
- pp " repeat rewrite spec_reduce_%i; repeat rewrite spec_reduce_%i; unfold to_Z; intros H1." i j;
- pp " apply F4 with (3:=w%i_spec)(4:=w%i_spec)(5:=w%i_spec); auto with zarith." j j i;
- pp " try (apply sym_equal; exact (spec_extend%in%i x))." i j;
- done;
- if i == size then
- begin
- pp " intros m y; unfold unsafe_shiftln, head0.";
- pp " repeat rewrite spec_reduce_n; unfold to_Z; intros H1.";
- pp " apply F4 with (3:=(wn_spec m))(4:=wn_spec m)(5:=w%i_spec); auto with zarith." size;
- pp " try (apply sym_equal; exact (spec_extend%in m x))." size;
- end
- else
- begin
- pp " intros m y; unfold unsafe_shiftln, head0.";
- pp " repeat rewrite spec_reduce_n; unfold to_Z; intros H1.";
- pp " apply F4 with (3:=(wn_spec m))(4:=wn_spec m)(5:=w%i_spec); auto with zarith." i;
- pp " change ([Nn m (extend%i m (extend%i %i x))] = [N%i x])." size i (size - i - 1) i;
- pp " rewrite <- (spec_extend%in m); rewrite <- spec_extend%in%i; auto." size i size;
- end
- done;
- pp " intros n x y; case y; clear y;";
- pp " intros y; unfold unsafe_shiftln, head0; try rewrite spec_reduce_n.";
- for i = 0 to size do
- pp " try rewrite spec_reduce_%i; unfold to_Z; intros H1." i;
- pp " apply F4 with (3:=(wn_spec n))(4:=w%i_spec)(5:=wn_spec n); auto with zarith." i;
- pp " rewrite (spec_zdigits w%i_spec)." i;
- pp " rewrite (spec_zdigits (wn_spec n)).";
- pp " apply Zle_trans with (2 := F6 n).";
- pp " change (znz_digits w%i_op) with %s." size (genxO (size - i) ("(znz_digits w" ^ (string_of_int i) ^ "_op)"));
- pp " repeat rewrite (fun x => Zpos_xO (xO x)).";
- pp " repeat rewrite (fun x y => Zpos_xO (@znz_digits x y)).";
- pp " assert (H: 0 <= Zpos (znz_digits w%i_op)); auto with zarith." i;
- if i == size then
- pp " change ([Nn n (extend%i n y)] = [N%i y])." size i
- else
- pp " change ([Nn n (extend%i n (extend%i %i y))] = [N%i y])." size i (size - i - 1) i;
- pp " rewrite <- (spec_extend%in n); auto." size;
- if i <> size then
- pp " try (rewrite <- spec_extend%in%i; auto)." i size;
- done;
- pp " generalize y; clear y; intros m y.";
- pp " repeat rewrite spec_reduce_n; unfold to_Z; intros H1.";
- pp " apply F4 with (3:=(wn_spec (Max.max n m)))(4:=wn_spec m)(5:=wn_spec n); auto with zarith.";
- pp " rewrite (spec_zdigits (wn_spec m)).";
- pp " rewrite (spec_zdigits (wn_spec (Max.max n m))).";
- pp " apply F5; auto with arith.";
- pp " exact (spec_cast_r n m y).";
- pp " exact (spec_cast_l n m x).";
- pp " Qed.";
- pr "";
-
- (* Double size *)
- pr " Definition double_size w := match w with";
- for i = 0 to size-1 do
- pr " | %s%i x => %s%i (WW (znz_0 w%i_op) x)" c i c (i + 1) i;
- done;
- pr " | %s%i x => %sn 0 (WW (znz_0 w%i_op) x)" c size c size;
- pr " | %sn n x => %sn (S n) (WW (znz_0 (make_op n)) x)" c c;
- pr " end.";
- pr "";
-
- pr " Theorem spec_double_size_digits:";
- pr " forall x, digits (double_size x) = xO (digits x).";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold double_size, digits; clear x; auto.";
- pp " intros n x; rewrite make_op_S; auto.";
- pp " Qed.";
- pr "";
-
-
- pr " Theorem spec_double_size: forall x, [double_size x] = [x].";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold double_size; clear x.";
- for i = 0 to size do
- pp " intros x; unfold to_Z, make_op;";
- pp " rewrite znz_to_Z_%i; rewrite (spec_0 w%i_spec); auto with zarith." (i + 1) i;
- done;
- pp " intros n x; unfold to_Z;";
- pp " generalize (znz_to_Z_n n); simpl word.";
- pp " intros HH; rewrite HH; clear HH.";
- pp " generalize (spec_0 (wn_spec n)); simpl word.";
- pp " intros HH; rewrite HH; clear HH; auto with zarith.";
- pp " Qed.";
- pr "";
-
-
- pr " Theorem spec_double_size_head0:";
- pr " forall x, 2 * [head0 x] <= [head0 (double_size x)].";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x.";
- pp " assert (F1:= spec_pos (head0 x)).";
- pp " assert (F2: 0 < Zpos (digits x)).";
- pp " red; auto.";
- pp " case (Zle_lt_or_eq _ _ (spec_pos x)); intros HH.";
- pp " generalize HH; rewrite <- (spec_double_size x); intros HH1.";
- pp " case (spec_head0 x HH); intros _ HH2.";
- pp " case (spec_head0 _ HH1).";
- pp " rewrite (spec_double_size x); rewrite (spec_double_size_digits x).";
- pp " intros HH3 _.";
- pp " case (Zle_or_lt ([head0 (double_size x)]) (2 * [head0 x])); auto; intros HH4.";
- pp " absurd (2 ^ (2 * [head0 x] )* [x] < 2 ^ [head0 (double_size x)] * [x]); auto.";
- pp " apply Zle_not_lt.";
- pp " apply Zmult_le_compat_r; auto with zarith.";
- pp " apply Zpower_le_monotone; auto; auto with zarith.";
- pp " generalize (spec_pos (head0 (double_size x))); auto with zarith.";
- pp " assert (HH5: 2 ^[head0 x] <= 2 ^(Zpos (digits x) - 1)).";
- pp " case (Zle_lt_or_eq 1 [x]); auto with zarith; intros HH5.";
- pp " apply Zmult_le_reg_r with (2 ^ 1); auto with zarith.";
- pp " rewrite <- (fun x y z => Zpower_exp x (y - z)); auto with zarith.";
- pp " assert (tmp: forall x, x - 1 + 1 = x); [intros; ring | rewrite tmp; clear tmp].";
- pp " apply Zle_trans with (2 := Zlt_le_weak _ _ HH2).";
- pp " apply Zmult_le_compat_l; auto with zarith.";
- pp " rewrite Zpower_1_r; auto with zarith.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " split; auto with zarith.";
- pp " case (Zle_or_lt (Zpos (digits x)) [head0 x]); auto with zarith; intros HH6.";
- pp " absurd (2 ^ Zpos (digits x) <= 2 ^ [head0 x] * [x]); auto with zarith.";
- pp " rewrite <- HH5; rewrite Zmult_1_r.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " rewrite (Zmult_comm 2).";
- pp " rewrite Zpower_mult; auto with zarith.";
- pp " rewrite Zpower_2.";
- pp " apply Zlt_le_trans with (2 := HH3).";
- pp " rewrite <- Zmult_assoc.";
- pp " replace (Zpos (xO (digits x)) - 1) with";
- pp " ((Zpos (digits x) - 1) + (Zpos (digits x))).";
- pp " rewrite Zpower_exp; auto with zarith.";
- pp " apply Zmult_lt_compat2; auto with zarith.";
- pp " split; auto with zarith.";
- pp " apply Zmult_lt_0_compat; auto with zarith.";
- pp " rewrite Zpos_xO; ring.";
- pp " apply Zlt_le_weak; auto.";
- pp " repeat rewrite spec_head00; auto.";
- pp " rewrite spec_double_size_digits.";
- pp " rewrite Zpos_xO; auto with zarith.";
- pp " rewrite spec_double_size; auto.";
- pp " Qed.";
- pr "";
-
- pr " Theorem spec_double_size_head0_pos:";
- pr " forall x, 0 < [head0 (double_size x)].";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x.";
- pp " assert (F: 0 < Zpos (digits x)).";
- pp " red; auto.";
- pp " case (Zle_lt_or_eq _ _ (spec_pos (head0 (double_size x)))); auto; intros F0.";
- pp " case (Zle_lt_or_eq _ _ (spec_pos (head0 x))); intros F1.";
- pp " apply Zlt_le_trans with (2 := (spec_double_size_head0 x)); auto with zarith.";
- pp " case (Zle_lt_or_eq _ _ (spec_pos x)); intros F3.";
- pp " generalize F3; rewrite <- (spec_double_size x); intros F4.";
- pp " absurd (2 ^ (Zpos (xO (digits x)) - 1) < 2 ^ (Zpos (digits x))).";
- pp " apply Zle_not_lt.";
- pp " apply Zpower_le_monotone; auto with zarith.";
- pp " split; auto with zarith.";
- pp " rewrite Zpos_xO; auto with zarith.";
- pp " case (spec_head0 x F3).";
- pp " rewrite <- F1; rewrite Zpower_0_r; rewrite Zmult_1_l; intros _ HH.";
- pp " apply Zle_lt_trans with (2 := HH).";
- pp " case (spec_head0 _ F4).";
- pp " rewrite (spec_double_size x); rewrite (spec_double_size_digits x).";
- pp " rewrite <- F0; rewrite Zpower_0_r; rewrite Zmult_1_l; auto.";
- pp " generalize F1; rewrite (spec_head00 _ (sym_equal F3)); auto with zarith.";
- pp " Qed.";
- pr "";
-
- (* even *)
- pr " Definition is_even x :=";
- pr " match x with";
- for i = 0 to size do
- pr " | %s%i wx => w%i_op.(znz_is_even) wx" c i i
- done;
- pr " | %sn n wx => (make_op n).(znz_is_even) wx" c;
- pr " end.";
- pr "";
-
-
- pr " Theorem spec_is_even: forall x,";
- pr " if is_even x then [x] mod 2 = 0 else [x] mod 2 = 1.";
- pa " Admitted.";
- pp " Proof.";
- pp " intros x; case x; unfold is_even, to_Z; clear x.";
- for i = 0 to size do
- pp " intros x; exact (spec_is_even w%i_spec x)." i;
- done;
- pp " intros n x; exact (spec_is_even (wn_spec n) x).";
- pp " Qed.";
- pr "";
-
- pr "End Make.";
- pr "";
-
+ pr " Eval lazy beta iota delta [reduce_n] in";
+ pr " reduce_n _ _ (N0 zero0) reduce_%i Nn n." (size + 1);
+ pr "";
+
+pr " Definition reduce n : dom_t n -> t :=";
+pr " match n with";
+for i = 0 to size do
+pr " | %i => reduce_%i" i i;
+done;
+pr " | %s(S n) => reduce_n n" (if size=0 then "" else "SizePlus ");
+pr " end.";
+pr "";
+
+pr " Ltac unfold_red := unfold reduce, %s." (iter_name 1 size "reduce_" ",");
+
+pr "
+ Ltac solve_red :=
+ let H := fresh in let G := fresh in
+ match goal with
+ | |- ?P (S ?n) => assert (H:P n) by solve_red
+ | _ => idtac
+ end;
+ intros n G x; destruct (le_lt_eq_dec _ _ G) as [LT|EQ];
+ solve [
+ apply (H _ (lt_n_Sm_le _ _ LT)) |
+ inversion LT |
+ subst; change (reduce 0 x = red_t 0 x); reflexivity |
+ specialize (H (pred n)); subst; destruct x;
+ [|unfold_red; rewrite H; auto]; reflexivity
+ ].
+
+ Lemma reduce_equiv : forall n x, n <= Size -> reduce n x = red_t n x.
+ Proof.
+ set (P N := forall n, n <= N -> forall x, reduce n x = red_t n x).
+ intros n x H. revert n H x. change (P Size). solve_red.
+ Qed.
+
+ Lemma spec_reduce_n : forall n x, [reduce_n n x] = [Nn n x].
+ Proof.
+ assert (H : forall x, reduce_%i x = red_t (SizePlus 1) x).
+ destruct x; [|unfold reduce_%i; rewrite (reduce_equiv Size)]; auto.
+ induction n.
+ intros. rewrite H. apply spec_red_t.
+ destruct x as [|xh xl].
+ simpl. rewrite make_op_S. exact ZnZ.spec_0.
+ fold word in *.
+ destruct xh; auto.
+ simpl reduce_n.
+ rewrite IHn.
+ rewrite spec_extend_WW; auto.
+ Qed.
+" (size+1) (size+1);
+
+pr
+" Lemma spec_reduce : forall n x, [reduce n x] = ZnZ.to_Z x.
+ Proof.
+ do_size (destruct n;
+ [intros; rewrite reduce_equiv;[apply spec_red_t|auto with arith]|]).
+ apply spec_reduce_n.
+ Qed.
+
+End Make.
+";
diff --git a/theories/Numbers/Natural/BigN/Nbasic.v b/theories/Numbers/Natural/BigN/Nbasic.v
index cdd41647..4717d0b2 100644
--- a/theories/Numbers/Natural/BigN/Nbasic.v
+++ b/theories/Numbers/Natural/BigN/Nbasic.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,9 +8,7 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: Nbasic.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Import ZArith.
+Require Import ZArith Ndigits.
Require Import BigNumPrelude.
Require Import Max.
Require Import DoubleType.
@@ -18,6 +16,26 @@ Require Import DoubleBase.
Require Import CyclicAxioms.
Require Import DoubleCyclic.
+Arguments mk_zn2z_ops [t] ops.
+Arguments mk_zn2z_ops_karatsuba [t] ops.
+Arguments mk_zn2z_specs [t ops] specs.
+Arguments mk_zn2z_specs_karatsuba [t ops] specs.
+Arguments ZnZ.digits [t] Ops.
+Arguments ZnZ.zdigits [t] Ops.
+
+Lemma Pshiftl_nat_Zpower : forall n p,
+ Zpos (Pos.shiftl_nat p n) = Zpos p * 2 ^ Z.of_nat n.
+Proof.
+ intros.
+ rewrite Z.mul_comm.
+ induction n. simpl; auto.
+ transitivity (2 * (2 ^ Z.of_nat n * Zpos p)).
+ rewrite <- IHn. auto.
+ rewrite Z.mul_assoc.
+ rewrite inj_S.
+ rewrite <- Z.pow_succ_r; auto with zarith.
+Qed.
+
(* To compute the necessary height *)
Fixpoint plength (p: positive) : positive :=
@@ -212,8 +230,8 @@ Fixpoint extend_tr (n : nat) {struct n}: (word w (S (n + m))) :=
End ExtendMax.
-Implicit Arguments extend_tr[w m].
-Implicit Arguments castm[w m n].
+Arguments extend_tr [w m] v n.
+Arguments castm [w m n] H x.
@@ -287,11 +305,7 @@ Section CompareRec.
Variable w_to_Z: w -> Z.
Variable w_to_Z_0: w_to_Z w_0 = 0.
Variable spec_compare0_m: forall x,
- match compare0_m x with
- Eq => w_to_Z w_0 = wm_to_Z x
- | Lt => w_to_Z w_0 < wm_to_Z x
- | Gt => w_to_Z w_0 > wm_to_Z x
- end.
+ compare0_m x = (w_to_Z w_0 ?= wm_to_Z x).
Variable wm_to_Z_pos: forall x, 0 <= wm_to_Z x < base wm_base.
Let double_to_Z := double_to_Z wm_base wm_to_Z.
@@ -308,29 +322,25 @@ Section CompareRec.
Lemma spec_compare0_mn: forall n x,
- match compare0_mn n x with
- Eq => 0 = double_to_Z n x
- | Lt => 0 < double_to_Z n x
- | Gt => 0 > double_to_Z n x
- end.
- Proof.
+ compare0_mn n x = (0 ?= double_to_Z n x).
+ Proof.
intros n; elim n; clear n; auto.
- intros x; generalize (spec_compare0_m x); rewrite w_to_Z_0; auto.
+ intros x; rewrite spec_compare0_m; rewrite w_to_Z_0; auto.
intros n Hrec x; case x; unfold compare0_mn; fold compare0_mn; auto.
+ fold word in *.
intros xh xl.
- generalize (Hrec xh); case compare0_mn; auto.
- generalize (Hrec xl); case compare0_mn; auto.
- simpl double_to_Z; intros H1 H2; rewrite H1; rewrite <- H2; auto.
- simpl double_to_Z; intros H1 H2; rewrite <- H2; auto.
- case (double_to_Z_pos n xl); auto with zarith.
- intros H1; simpl double_to_Z.
- set (u := DoubleBase.double_wB wm_base n).
- case (double_to_Z_pos n xl); intros H2 H3.
- assert (0 < u); auto with zarith.
- unfold u, DoubleBase.double_wB, base; auto with zarith.
+ rewrite 2 Hrec.
+ simpl double_to_Z.
+ set (wB := DoubleBase.double_wB wm_base n).
+ case Zcompare_spec; intros Cmp.
+ rewrite <- Cmp. reflexivity.
+ symmetry. apply Zgt_lt, Zlt_gt. (* ;-) *)
+ assert (0 < wB).
+ unfold wB, DoubleBase.double_wB, base; auto with zarith.
change 0 with (0 + 0); apply Zplus_lt_le_compat; auto with zarith.
apply Zmult_lt_0_compat; auto with zarith.
- case (double_to_Z_pos n xh); auto with zarith.
+ case (double_to_Z_pos n xl); auto with zarith.
+ case (double_to_Z_pos n xh); intros; exfalso; omega.
Qed.
Fixpoint compare_mn_1 (n:nat) : word wm n -> w -> comparison :=
@@ -348,17 +358,9 @@ Section CompareRec.
end.
Variable spec_compare: forall x y,
- match compare x y with
- Eq => w_to_Z x = w_to_Z y
- | Lt => w_to_Z x < w_to_Z y
- | Gt => w_to_Z x > w_to_Z y
- end.
+ compare x y = Zcompare (w_to_Z x) (w_to_Z y).
Variable spec_compare_m: forall x y,
- match compare_m x y with
- Eq => wm_to_Z x = w_to_Z y
- | Lt => wm_to_Z x < w_to_Z y
- | Gt => wm_to_Z x > w_to_Z y
- end.
+ compare_m x y = Zcompare (wm_to_Z x) (w_to_Z y).
Variable wm_base_lt: forall x,
0 <= w_to_Z x < base (wm_base).
@@ -369,8 +371,8 @@ Section CompareRec.
intros n (H0, H); split; auto.
apply Zlt_le_trans with (1:= H).
unfold double_wB, DoubleBase.double_wB; simpl.
- rewrite base_xO.
- set (u := base (double_digits wm_base n)).
+ rewrite Pshiftl_nat_S, base_xO.
+ set (u := base (Pos.shiftl_nat wm_base n)).
assert (0 < u).
unfold u, base; auto with zarith.
replace (u^2) with (u * u); simpl; auto with zarith.
@@ -380,26 +382,23 @@ Section CompareRec.
Lemma spec_compare_mn_1: forall n x y,
- match compare_mn_1 n x y with
- Eq => double_to_Z n x = w_to_Z y
- | Lt => double_to_Z n x < w_to_Z y
- | Gt => double_to_Z n x > w_to_Z y
- end.
+ compare_mn_1 n x y = Zcompare (double_to_Z n x) (w_to_Z y).
Proof.
intros n; elim n; simpl; auto; clear n.
intros n Hrec x; case x; clear x; auto.
- intros y; generalize (spec_compare w_0 y); rewrite w_to_Z_0; case compare; auto.
- intros xh xl y; simpl; generalize (spec_compare0_mn n xh); case compare0_mn; intros H1b.
+ intros y; rewrite spec_compare; rewrite w_to_Z_0. reflexivity.
+ intros xh xl y; simpl;
+ rewrite spec_compare0_mn, Hrec. case Zcompare_spec.
+ intros H1b.
rewrite <- H1b; rewrite Zmult_0_l; rewrite Zplus_0_l; auto.
- apply Hrec.
- apply Zlt_gt.
+ symmetry. apply Zlt_gt.
case (double_wB_lt n y); intros _ H0.
apply Zlt_le_trans with (1:= H0).
fold double_wB.
case (double_to_Z_pos n xl); intros H1 H2.
apply Zle_trans with (double_to_Z n xh * double_wB n); auto with zarith.
apply Zle_trans with (1 * double_wB n); auto with zarith.
- case (double_to_Z_pos n xh); auto with zarith.
+ case (double_to_Z_pos n xh); intros; exfalso; omega.
Qed.
End CompareRec.
@@ -433,22 +432,6 @@ Section AddS.
End AddS.
-
- Lemma spec_opp: forall u x y,
- match u with
- | Eq => y = x
- | Lt => y < x
- | Gt => y > x
- end ->
- match CompOpp u with
- | Eq => x = y
- | Lt => x < y
- | Gt => x > y
- end.
- Proof.
- intros u x y; case u; simpl; auto with zarith.
- Qed.
-
Fixpoint length_pos x :=
match x with xH => O | xO x1 => S (length_pos x1) | xI x1 => S (length_pos x1) end.
@@ -474,34 +457,112 @@ End AddS.
Variable w: Type.
- Theorem digits_zop: forall w (x: znz_op w),
- znz_digits (mk_zn2z_op x) = xO (znz_digits x).
+ Theorem digits_zop: forall t (ops : ZnZ.Ops t),
+ ZnZ.digits (mk_zn2z_ops ops) = xO (ZnZ.digits ops).
+ Proof.
intros ww x; auto.
Qed.
- Theorem digits_kzop: forall w (x: znz_op w),
- znz_digits (mk_zn2z_op_karatsuba x) = xO (znz_digits x).
+ Theorem digits_kzop: forall t (ops : ZnZ.Ops t),
+ ZnZ.digits (mk_zn2z_ops_karatsuba ops) = xO (ZnZ.digits ops).
+ Proof.
intros ww x; auto.
Qed.
- Theorem make_zop: forall w (x: znz_op w),
- znz_to_Z (mk_zn2z_op x) =
+ Theorem make_zop: forall t (ops : ZnZ.Ops t),
+ @ZnZ.to_Z _ (mk_zn2z_ops ops) =
fun z => match z with
- W0 => 0
- | WW xh xl => znz_to_Z x xh * base (znz_digits x)
- + znz_to_Z x xl
+ | W0 => 0
+ | WW xh xl => ZnZ.to_Z xh * base (ZnZ.digits ops)
+ + ZnZ.to_Z xl
end.
+ Proof.
intros ww x; auto.
Qed.
- Theorem make_kzop: forall w (x: znz_op w),
- znz_to_Z (mk_zn2z_op_karatsuba x) =
+ Theorem make_kzop: forall t (ops: ZnZ.Ops t),
+ @ZnZ.to_Z _ (mk_zn2z_ops_karatsuba ops) =
fun z => match z with
- W0 => 0
- | WW xh xl => znz_to_Z x xh * base (znz_digits x)
- + znz_to_Z x xl
+ | W0 => 0
+ | WW xh xl => ZnZ.to_Z xh * base (ZnZ.digits ops)
+ + ZnZ.to_Z xl
end.
+ Proof.
intros ww x; auto.
Qed.
End SimplOp.
+
+(** Abstract vision of a datatype of arbitrary-large numbers.
+ Concrete operations can be derived from these generic
+ fonctions, in particular from [iter_t] and [same_level].
+*)
+
+Module Type NAbstract.
+
+(** The domains: a sequence of [Z/nZ] structures *)
+
+Parameter dom_t : nat -> Type.
+Declare Instance dom_op n : ZnZ.Ops (dom_t n).
+Declare Instance dom_spec n : ZnZ.Specs (dom_op n).
+
+Axiom digits_dom_op : forall n,
+ ZnZ.digits (dom_op n) = Pos.shiftl_nat (ZnZ.digits (dom_op 0)) n.
+
+(** The type [t] of arbitrary-large numbers, with abstract constructor [mk_t]
+ and destructor [destr_t] and iterator [iter_t] *)
+
+Parameter t : Type.
+
+Parameter mk_t : forall (n:nat), dom_t n -> t.
+
+Inductive View_t : t -> Prop :=
+ Mk_t : forall n (x : dom_t n), View_t (mk_t n x).
+
+Axiom destr_t : forall x, View_t x. (* i.e. every x is a (mk_t n xw) *)
+
+Parameter iter_t : forall {A:Type}(f : forall n, dom_t n -> A), t -> A.
+
+Axiom iter_mk_t : forall A (f:forall n, dom_t n -> A),
+ forall n x, iter_t f (mk_t n x) = f n x.
+
+(** Conversion to [ZArith] *)
+
+Parameter to_Z : t -> Z.
+Local Notation "[ x ]" := (to_Z x).
+
+Axiom spec_mk_t : forall n x, [mk_t n x] = ZnZ.to_Z x.
+
+(** [reduce] is like [mk_t], but try to minimise the level of the number *)
+
+Parameter reduce : forall (n:nat), dom_t n -> t.
+Axiom spec_reduce : forall n x, [reduce n x] = ZnZ.to_Z x.
+
+(** Number of level in the tree representation of a number.
+ NB: This function isn't a morphism for setoid [eq]. *)
+
+Definition level := iter_t (fun n _ => n).
+
+(** [same_level] and its rich specification, indexed by [level] *)
+
+Parameter same_level : forall {A:Type}
+ (f : forall n, dom_t n -> dom_t n -> A), t -> t -> A.
+
+Axiom spec_same_level_dep :
+ forall res
+ (P : nat -> Z -> Z -> res -> Prop)
+ (Pantimon : forall n m z z' r, (n <= m)%nat -> P m z z' r -> P n z z' r)
+ (f : forall n, dom_t n -> dom_t n -> res)
+ (Pf: forall n x y, P n (ZnZ.to_Z x) (ZnZ.to_Z y) (f n x y)),
+ forall x y, P (level x) [x] [y] (same_level f x y).
+
+(** [mk_t_S] : building a number of the next level *)
+
+Parameter mk_t_S : forall (n:nat), zn2z (dom_t n) -> t.
+
+Axiom spec_mk_t_S : forall n (x:zn2z (dom_t n)),
+ [mk_t_S n x] = zn2z_to_Z (base (ZnZ.digits (dom_op n))) ZnZ.to_Z x.
+
+Axiom mk_t_S_level : forall n x, level (mk_t_S n x) = S n.
+
+End NAbstract.
diff --git a/theories/Numbers/Natural/Binary/NBinary.v b/theories/Numbers/Natural/Binary/NBinary.v
index 029fdfca..43ca67dd 100644
--- a/theories/Numbers/Natural/Binary/NBinary.v
+++ b/theories/Numbers/Natural/Binary/NBinary.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,150 +8,15 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NBinary.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import BinPos.
Require Export BinNat.
Require Import NAxioms NProperties.
Local Open Scope N_scope.
-(** * Implementation of [NAxiomsSig] module type via [BinNat.N] *)
-
-Module NBinaryAxiomsMod <: NAxiomsSig.
-
-(** Bi-directional induction. *)
-
-Theorem bi_induction :
- forall A : N -> Prop, Proper (eq==>iff) A ->
- A N0 -> (forall n, A n <-> A (Nsucc n)) -> forall n : N, A n.
-Proof.
-intros A A_wd A0 AS. apply Nrect. assumption. intros; now apply -> AS.
-Qed.
-
-(** Basic operations. *)
-
-Definition eq_equiv : Equivalence (@eq N) := eq_equivalence.
-Local Obligation Tactic := simpl_relation.
-Program Instance succ_wd : Proper (eq==>eq) Nsucc.
-Program Instance pred_wd : Proper (eq==>eq) Npred.
-Program Instance add_wd : Proper (eq==>eq==>eq) Nplus.
-Program Instance sub_wd : Proper (eq==>eq==>eq) Nminus.
-Program Instance mul_wd : Proper (eq==>eq==>eq) Nmult.
-
-Definition pred_succ := Npred_succ.
-Definition add_0_l := Nplus_0_l.
-Definition add_succ_l := Nplus_succ.
-Definition sub_0_r := Nminus_0_r.
-Definition sub_succ_r := Nminus_succ_r.
-Definition mul_0_l := Nmult_0_l.
-Definition mul_succ_l n m := eq_trans (Nmult_Sn_m n m) (Nplus_comm _ _).
-
-(** Order *)
-
-Program Instance lt_wd : Proper (eq==>eq==>iff) Nlt.
-
-Definition lt_eq_cases := Nle_lteq.
-Definition lt_irrefl := Nlt_irrefl.
-
-Theorem lt_succ_r : forall n m, n < (Nsucc m) <-> n <= m.
-Proof.
-intros n m; unfold Nlt, Nle; destruct n as [| p]; destruct m as [| q]; simpl;
-split; intro H; try reflexivity; try discriminate.
-destruct p; simpl; intros; discriminate. exfalso; now apply H.
-apply -> Pcompare_p_Sq in H. destruct H as [H | H].
-now rewrite H. now rewrite H, Pcompare_refl.
-apply <- Pcompare_p_Sq. case_eq ((p ?= q)%positive Eq); intro H1.
-right; now apply Pcompare_Eq_eq. now left. exfalso; now apply H.
-Qed.
-
-Theorem min_l : forall n m, n <= m -> Nmin n m = n.
-Proof.
-unfold Nmin, Nle; intros n m H.
-destruct (n ?= m); try reflexivity. now elim H.
-Qed.
-
-Theorem min_r : forall n m, m <= n -> Nmin n m = m.
-Proof.
-unfold Nmin, Nle; intros n m H.
-case_eq (n ?= m); intro H1; try reflexivity.
-now apply -> Ncompare_eq_correct.
-rewrite <- Ncompare_antisym, H1 in H; elim H; auto.
-Qed.
-
-Theorem max_l : forall n m, m <= n -> Nmax n m = n.
-Proof.
-unfold Nmax, Nle; intros n m H.
-case_eq (n ?= m); intro H1; try reflexivity.
-symmetry; now apply -> Ncompare_eq_correct.
-rewrite <- Ncompare_antisym, H1 in H; elim H; auto.
-Qed.
-
-Theorem max_r : forall n m : N, n <= m -> Nmax n m = m.
-Proof.
-unfold Nmax, Nle; intros n m H.
-destruct (n ?= m); try reflexivity. now elim H.
-Qed.
-
-(** Part specific to natural numbers, not integers. *)
-
-Theorem pred_0 : Npred 0 = 0.
-Proof.
-reflexivity.
-Qed.
-
-Definition recursion (A : Type) : A -> (N -> A -> A) -> N -> A :=
- Nrect (fun _ => A).
-Implicit Arguments recursion [A].
-
-Instance recursion_wd A (Aeq : relation A) :
- Proper (Aeq==>(eq==>Aeq==>Aeq)==>eq==>Aeq) (@recursion A).
-Proof.
-intros a a' Eaa' f f' Eff'.
-intro x; pattern x; apply Nrect.
-intros x' H; now rewrite <- H.
-clear x.
-intros x IH x' H; rewrite <- H.
-unfold recursion in *. do 2 rewrite Nrect_step.
-now apply Eff'; [| apply IH].
-Qed.
-
-Theorem recursion_0 :
- forall (A : Type) (a : A) (f : N -> A -> A), recursion a f N0 = a.
-Proof.
-intros A a f; unfold recursion; now rewrite Nrect_base.
-Qed.
-
-Theorem recursion_succ :
- forall (A : Type) (Aeq : relation A) (a : A) (f : N -> A -> A),
- Aeq a a -> Proper (eq==>Aeq==>Aeq) f ->
- forall n : N, Aeq (recursion a f (Nsucc n)) (f n (recursion a f n)).
-Proof.
-unfold recursion; intros A Aeq a f EAaa f_wd n; pattern n; apply Nrect.
-rewrite Nrect_step; rewrite Nrect_base; now apply f_wd.
-clear n; intro n; do 2 rewrite Nrect_step; intro IH. apply f_wd; [reflexivity|].
-now rewrite Nrect_step.
-Qed.
-
-(** The instantiation of operations.
- Placing them at the very end avoids having indirections in above lemmas. *)
-
-Definition t := N.
-Definition eq := @eq N.
-Definition zero := N0.
-Definition succ := Nsucc.
-Definition pred := Npred.
-Definition add := Nplus.
-Definition sub := Nminus.
-Definition mul := Nmult.
-Definition lt := Nlt.
-Definition le := Nle.
-Definition min := Nmin.
-Definition max := Nmax.
-
-End NBinaryAxiomsMod.
+(** * [BinNat.N] already implements [NAxiomSig] *)
-Module Export NBinaryPropMod := NPropFunct NBinaryAxiomsMod.
+Module N <: NAxiomsSig := N.
(*
Require Import NDefOps.
diff --git a/theories/Numbers/Natural/Peano/NPeano.v b/theories/Numbers/Natural/Peano/NPeano.v
index fbc63c04..d5df6329 100644
--- a/theories/Numbers/Natural/Peano/NPeano.v
+++ b/theories/Numbers/Natural/Peano/NPeano.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,13 +8,571 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NPeano.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
+Require Import
+ Bool Peano Peano_dec Compare_dec Plus Mult Minus Le Lt EqNat Div2 Wf_nat
+ NAxioms NProperties.
-Require Import Arith MinMax NAxioms NProperties.
+(** Functions not already defined *)
+
+Fixpoint leb n m :=
+ match n, m with
+ | O, _ => true
+ | _, O => false
+ | S n', S m' => leb n' m'
+ end.
+
+Definition ltb n m := leb (S n) m.
+
+Infix "<=?" := leb (at level 70) : nat_scope.
+Infix "<?" := ltb (at level 70) : nat_scope.
+
+Lemma leb_le n m : (n <=? m) = true <-> n <= m.
+Proof.
+ revert m.
+ induction n. split; auto with arith.
+ destruct m; simpl. now split.
+ rewrite IHn. split; auto with arith.
+Qed.
+
+Lemma ltb_lt n m : (n <? m) = true <-> n < m.
+Proof.
+ unfold ltb, lt. apply leb_le.
+Qed.
+
+Fixpoint pow n m :=
+ match m with
+ | O => 1
+ | S m => n * (pow n m)
+ end.
+
+Infix "^" := pow : nat_scope.
+
+Lemma pow_0_r : forall a, a^0 = 1.
+Proof. reflexivity. Qed.
+
+Lemma pow_succ_r : forall a b, 0<=b -> a^(S b) = a * a^b.
+Proof. reflexivity. Qed.
+
+Definition square n := n * n.
+
+Lemma square_spec n : square n = n * n.
+Proof. reflexivity. Qed.
+
+Definition Even n := exists m, n = 2*m.
+Definition Odd n := exists m, n = 2*m+1.
+
+Fixpoint even n :=
+ match n with
+ | O => true
+ | 1 => false
+ | S (S n') => even n'
+ end.
+
+Definition odd n := negb (even n).
+
+Lemma even_spec : forall n, even n = true <-> Even n.
+Proof.
+ fix 1.
+ destruct n as [|[|n]]; simpl; try rewrite even_spec; split.
+ now exists 0.
+ trivial.
+ discriminate.
+ intros (m,H). destruct m. discriminate.
+ simpl in H. rewrite <- plus_n_Sm in H. discriminate.
+ intros (m,H). exists (S m). rewrite H. simpl. now rewrite plus_n_Sm.
+ intros (m,H). destruct m. discriminate. exists m.
+ simpl in H. rewrite <- plus_n_Sm in H. inversion H. reflexivity.
+Qed.
+
+Lemma odd_spec : forall n, odd n = true <-> Odd n.
+Proof.
+ unfold odd.
+ fix 1.
+ destruct n as [|[|n]]; simpl; try rewrite odd_spec; split.
+ discriminate.
+ intros (m,H). rewrite <- plus_n_Sm in H; discriminate.
+ now exists 0.
+ trivial.
+ intros (m,H). exists (S m). rewrite H. simpl. now rewrite <- (plus_n_Sm m).
+ intros (m,H). destruct m. discriminate. exists m.
+ simpl in H. rewrite <- plus_n_Sm in H. inversion H. simpl.
+ now rewrite <- !plus_n_Sm, <- !plus_n_O.
+Qed.
+
+Lemma Even_equiv : forall n, Even n <-> Even.even n.
+Proof.
+ split. intros (p,->). apply Even.even_mult_l. do 3 constructor.
+ intros H. destruct (even_2n n H) as (p,->).
+ exists p. unfold double. simpl. now rewrite <- plus_n_O.
+Qed.
+
+Lemma Odd_equiv : forall n, Odd n <-> Even.odd n.
+Proof.
+ split. intros (p,->). rewrite <- plus_n_Sm, <- plus_n_O.
+ apply Even.odd_S. apply Even.even_mult_l. do 3 constructor.
+ intros H. destruct (odd_S2n n H) as (p,->).
+ exists p. unfold double. simpl. now rewrite <- plus_n_Sm, <- !plus_n_O.
+Qed.
+
+(* A linear, tail-recursive, division for nat.
+
+ In [divmod], [y] is the predecessor of the actual divisor,
+ and [u] is [y] minus the real remainder
+*)
+
+Fixpoint divmod x y q u :=
+ match x with
+ | 0 => (q,u)
+ | S x' => match u with
+ | 0 => divmod x' y (S q) y
+ | S u' => divmod x' y q u'
+ end
+ end.
+
+Definition div x y :=
+ match y with
+ | 0 => y
+ | S y' => fst (divmod x y' 0 y')
+ end.
+
+Definition modulo x y :=
+ match y with
+ | 0 => y
+ | S y' => y' - snd (divmod x y' 0 y')
+ end.
+
+Infix "/" := div : nat_scope.
+Infix "mod" := modulo (at level 40, no associativity) : nat_scope.
+
+Lemma divmod_spec : forall x y q u, u <= y ->
+ let (q',u') := divmod x y q u in
+ x + (S y)*q + (y-u) = (S y)*q' + (y-u') /\ u' <= y.
+Proof.
+ induction x. simpl. intuition.
+ intros y q u H. destruct u; simpl divmod.
+ generalize (IHx y (S q) y (le_n y)). destruct divmod as (q',u').
+ intros (EQ,LE); split; trivial.
+ rewrite <- EQ, <- minus_n_O, minus_diag, <- plus_n_O.
+ now rewrite !plus_Sn_m, plus_n_Sm, <- plus_assoc, mult_n_Sm.
+ generalize (IHx y q u (le_Sn_le _ _ H)). destruct divmod as (q',u').
+ intros (EQ,LE); split; trivial.
+ rewrite <- EQ.
+ rewrite !plus_Sn_m, plus_n_Sm. f_equal. now apply minus_Sn_m.
+Qed.
+
+Lemma div_mod : forall x y, y<>0 -> x = y*(x/y) + x mod y.
+Proof.
+ intros x y Hy.
+ destruct y; [ now elim Hy | clear Hy ].
+ unfold div, modulo.
+ generalize (divmod_spec x y 0 y (le_n y)).
+ destruct divmod as (q,u).
+ intros (U,V).
+ simpl in *.
+ now rewrite <- mult_n_O, minus_diag, <- !plus_n_O in U.
+Qed.
+
+Lemma mod_bound_pos : forall x y, 0<=x -> 0<y -> 0 <= x mod y < y.
+Proof.
+ intros x y Hx Hy. split. auto with arith.
+ destruct y; [ now elim Hy | clear Hy ].
+ unfold modulo.
+ apply le_n_S, le_minus.
+Qed.
+
+(** Square root *)
+
+(** The following square root function is linear (and tail-recursive).
+ With Peano representation, we can't do better. For faster algorithm,
+ see Psqrt/Zsqrt/Nsqrt...
+
+ We search the square root of n = k + p^2 + (q - r)
+ with q = 2p and 0<=r<=q. We start with p=q=r=0, hence
+ looking for the square root of n = k. Then we progressively
+ decrease k and r. When k = S k' and r=0, it means we can use (S p)
+ as new sqrt candidate, since (S k')+p^2+2p = k'+(S p)^2.
+ When k reaches 0, we have found the biggest p^2 square contained
+ in n, hence the square root of n is p.
+*)
+
+Fixpoint sqrt_iter k p q r :=
+ match k with
+ | O => p
+ | S k' => match r with
+ | O => sqrt_iter k' (S p) (S (S q)) (S (S q))
+ | S r' => sqrt_iter k' p q r'
+ end
+ end.
+
+Definition sqrt n := sqrt_iter n 0 0 0.
+
+Lemma sqrt_iter_spec : forall k p q r,
+ q = p+p -> r<=q ->
+ let s := sqrt_iter k p q r in
+ s*s <= k + p*p + (q - r) < (S s)*(S s).
+Proof.
+ induction k.
+ (* k = 0 *)
+ simpl; intros p q r Hq Hr.
+ split.
+ apply le_plus_l.
+ apply le_lt_n_Sm.
+ rewrite <- mult_n_Sm.
+ rewrite plus_assoc, (plus_comm p), <- plus_assoc.
+ apply plus_le_compat; trivial.
+ rewrite <- Hq. apply le_minus.
+ (* k = S k' *)
+ destruct r.
+ (* r = 0 *)
+ intros Hq _.
+ replace (S k + p*p + (q-0)) with (k + (S p)*(S p) + (S (S q) - S (S q))).
+ apply IHk.
+ simpl. rewrite <- plus_n_Sm. congruence.
+ auto with arith.
+ rewrite minus_diag, <- minus_n_O, <- plus_n_O. simpl.
+ rewrite <- plus_n_Sm; f_equal. rewrite <- plus_assoc; f_equal.
+ rewrite <- mult_n_Sm, (plus_comm p), <- plus_assoc. congruence.
+ (* r = S r' *)
+ intros Hq Hr.
+ replace (S k + p*p + (q-S r)) with (k + p*p + (q - r)).
+ apply IHk; auto with arith.
+ simpl. rewrite plus_n_Sm. f_equal. rewrite minus_Sn_m; auto.
+Qed.
+
+Lemma sqrt_spec : forall n,
+ (sqrt n)*(sqrt n) <= n < S (sqrt n) * S (sqrt n).
+Proof.
+ intros.
+ set (s:=sqrt n).
+ replace n with (n + 0*0 + (0-0)).
+ apply sqrt_iter_spec; auto.
+ simpl. now rewrite <- 2 plus_n_O.
+Qed.
+
+(** A linear tail-recursive base-2 logarithm
+
+ In [log2_iter], we maintain the logarithm [p] of the counter [q],
+ while [r] is the distance between [q] and the next power of 2,
+ more precisely [q + S r = 2^(S p)] and [r<2^p]. At each
+ recursive call, [q] goes up while [r] goes down. When [r]
+ is 0, we know that [q] has almost reached a power of 2,
+ and we increase [p] at the next call, while resetting [r]
+ to [q].
+
+ Graphically (numbers are [q], stars are [r]) :
+
+<<
+ 10
+ 9
+ 8
+ 7 *
+ 6 *
+ 5 ...
+ 4
+ 3 *
+ 2 *
+ 1 * *
+0 * * *
+>>
+
+ We stop when [k], the global downward counter reaches 0.
+ At that moment, [q] is the number we're considering (since
+ [k+q] is invariant), and [p] its logarithm.
+*)
+
+Fixpoint log2_iter k p q r :=
+ match k with
+ | O => p
+ | S k' => match r with
+ | O => log2_iter k' (S p) (S q) q
+ | S r' => log2_iter k' p (S q) r'
+ end
+ end.
+
+Definition log2 n := log2_iter (pred n) 0 1 0.
+
+Lemma log2_iter_spec : forall k p q r,
+ 2^(S p) = q + S r -> r < 2^p ->
+ let s := log2_iter k p q r in
+ 2^s <= k + q < 2^(S s).
+Proof.
+ induction k.
+ (* k = 0 *)
+ intros p q r EQ LT. simpl log2_iter. cbv zeta.
+ split.
+ rewrite plus_O_n.
+ apply plus_le_reg_l with (2^p).
+ simpl pow in EQ. rewrite <- plus_n_O in EQ. rewrite EQ.
+ rewrite plus_comm. apply plus_le_compat_r. now apply lt_le_S.
+ rewrite EQ, plus_comm. apply plus_lt_compat_l. apply lt_0_Sn.
+ (* k = S k' *)
+ intros p q r EQ LT. destruct r.
+ (* r = 0 *)
+ rewrite <- plus_n_Sm, <- plus_n_O in EQ.
+ rewrite plus_Sn_m, plus_n_Sm. apply IHk.
+ rewrite <- EQ. remember (S p) as p'; simpl. now rewrite <- plus_n_O.
+ unfold lt. now rewrite EQ.
+ (* r = S r' *)
+ rewrite plus_Sn_m, plus_n_Sm. apply IHk.
+ now rewrite plus_Sn_m, plus_n_Sm.
+ unfold lt.
+ now apply lt_le_weak.
+Qed.
+
+Lemma log2_spec : forall n, 0<n ->
+ 2^(log2 n) <= n < 2^(S (log2 n)).
+Proof.
+ intros.
+ set (s:=log2 n).
+ replace n with (pred n + 1).
+ apply log2_iter_spec; auto.
+ rewrite <- plus_n_Sm, <- plus_n_O.
+ symmetry. now apply S_pred with 0.
+Qed.
+
+Lemma log2_nonpos : forall n, n<=0 -> log2 n = 0.
+Proof.
+ inversion 1; now subst.
+Qed.
+
+(** * Gcd *)
+
+(** We use Euclid algorithm, which is normally not structural,
+ but Coq is now clever enough to accept this (behind modulo
+ there is a subtraction, which now preserves being a subterm)
+*)
+
+Fixpoint gcd a b :=
+ match a with
+ | O => b
+ | S a' => gcd (b mod (S a')) (S a')
+ end.
+
+Definition divide x y := exists z, y=z*x.
+Notation "( x | y )" := (divide x y) (at level 0) : nat_scope.
+
+Lemma gcd_divide : forall a b, (gcd a b | a) /\ (gcd a b | b).
+Proof.
+ fix 1.
+ intros [|a] b; simpl.
+ split.
+ now exists 0.
+ exists 1. simpl. now rewrite <- plus_n_O.
+ fold (b mod (S a)).
+ destruct (gcd_divide (b mod (S a)) (S a)) as (H,H').
+ set (a':=S a) in *.
+ split; auto.
+ rewrite (div_mod b a') at 2 by discriminate.
+ destruct H as (u,Hu), H' as (v,Hv).
+ rewrite mult_comm.
+ exists ((b/a')*v + u).
+ rewrite mult_plus_distr_r.
+ now rewrite <- mult_assoc, <- Hv, <- Hu.
+Qed.
+
+Lemma gcd_divide_l : forall a b, (gcd a b | a).
+Proof.
+ intros. apply gcd_divide.
+Qed.
+
+Lemma gcd_divide_r : forall a b, (gcd a b | b).
+Proof.
+ intros. apply gcd_divide.
+Qed.
+
+Lemma gcd_greatest : forall a b c, (c|a) -> (c|b) -> (c|gcd a b).
+Proof.
+ fix 1.
+ intros [|a] b; simpl; auto.
+ fold (b mod (S a)).
+ intros c H H'. apply gcd_greatest; auto.
+ set (a':=S a) in *.
+ rewrite (div_mod b a') in H' by discriminate.
+ destruct H as (u,Hu), H' as (v,Hv).
+ exists (v - (b/a')*u).
+ rewrite mult_comm in Hv.
+ now rewrite mult_minus_distr_r, <- Hv, <-mult_assoc, <-Hu, minus_plus.
+Qed.
+
+(** * Bitwise operations *)
+
+(** We provide here some bitwise operations for unary numbers.
+ Some might be really naive, they are just there for fullfiling
+ the same interface as other for natural representations. As
+ soon as binary representations such as NArith are available,
+ it is clearly better to convert to/from them and use their ops.
+*)
+
+Fixpoint testbit a n :=
+ match n with
+ | O => odd a
+ | S n => testbit (div2 a) n
+ end.
+
+Definition shiftl a n := iter_nat n _ double a.
+Definition shiftr a n := iter_nat n _ div2 a.
+
+Fixpoint bitwise (op:bool->bool->bool) n a b :=
+ match n with
+ | O => O
+ | S n' =>
+ (if op (odd a) (odd b) then 1 else 0) +
+ 2*(bitwise op n' (div2 a) (div2 b))
+ end.
+
+Definition land a b := bitwise andb a a b.
+Definition lor a b := bitwise orb (max a b) a b.
+Definition ldiff a b := bitwise (fun b b' => b && negb b') a a b.
+Definition lxor a b := bitwise xorb (max a b) a b.
+
+Lemma double_twice : forall n, double n = 2*n.
+Proof.
+ simpl; intros. now rewrite <- plus_n_O.
+Qed.
+
+Lemma testbit_0_l : forall n, testbit 0 n = false.
+Proof.
+ now induction n.
+Qed.
+
+Lemma testbit_odd_0 a : testbit (2*a+1) 0 = true.
+Proof.
+ unfold testbit. rewrite odd_spec. now exists a.
+Qed.
+
+Lemma testbit_even_0 a : testbit (2*a) 0 = false.
+Proof.
+ unfold testbit, odd. rewrite (proj2 (even_spec _)); trivial.
+ now exists a.
+Qed.
+
+Lemma testbit_odd_succ a n : testbit (2*a+1) (S n) = testbit a n.
+Proof.
+ unfold testbit; fold testbit.
+ rewrite <- plus_n_Sm, <- plus_n_O. f_equal.
+ apply div2_double_plus_one.
+Qed.
+
+Lemma testbit_even_succ a n : testbit (2*a) (S n) = testbit a n.
+Proof.
+ unfold testbit; fold testbit. f_equal. apply div2_double.
+Qed.
+
+Lemma shiftr_spec : forall a n m,
+ testbit (shiftr a n) m = testbit a (m+n).
+Proof.
+ induction n; intros m. trivial.
+ now rewrite <- plus_n_O.
+ now rewrite <- plus_n_Sm, <- plus_Sn_m, <- IHn.
+Qed.
+
+Lemma shiftl_spec_high : forall a n m, n<=m ->
+ testbit (shiftl a n) m = testbit a (m-n).
+Proof.
+ induction n; intros m H. trivial.
+ now rewrite <- minus_n_O.
+ destruct m. inversion H.
+ simpl. apply le_S_n in H.
+ change (shiftl a (S n)) with (double (shiftl a n)).
+ rewrite double_twice, div2_double. now apply IHn.
+Qed.
+
+Lemma shiftl_spec_low : forall a n m, m<n ->
+ testbit (shiftl a n) m = false.
+Proof.
+ induction n; intros m H. inversion H.
+ change (shiftl a (S n)) with (double (shiftl a n)).
+ destruct m; simpl.
+ unfold odd. apply negb_false_iff.
+ apply even_spec. exists (shiftl a n). apply double_twice.
+ rewrite double_twice, div2_double. apply IHn.
+ now apply lt_S_n.
+Qed.
+
+Lemma div2_bitwise : forall op n a b,
+ div2 (bitwise op (S n) a b) = bitwise op n (div2 a) (div2 b).
+Proof.
+ intros. unfold bitwise; fold bitwise.
+ destruct (op (odd a) (odd b)).
+ now rewrite div2_double_plus_one.
+ now rewrite plus_O_n, div2_double.
+Qed.
+
+Lemma odd_bitwise : forall op n a b,
+ odd (bitwise op (S n) a b) = op (odd a) (odd b).
+Proof.
+ intros. unfold bitwise; fold bitwise.
+ destruct (op (odd a) (odd b)).
+ apply odd_spec. rewrite plus_comm. eexists; eauto.
+ unfold odd. apply negb_false_iff. apply even_spec.
+ rewrite plus_O_n; eexists; eauto.
+Qed.
+
+Lemma div2_decr : forall a n, a <= S n -> div2 a <= n.
+Proof.
+ destruct a; intros. apply le_0_n.
+ apply le_trans with a.
+ apply lt_n_Sm_le, lt_div2, lt_0_Sn. now apply le_S_n.
+Qed.
+
+Lemma testbit_bitwise_1 : forall op, (forall b, op false b = false) ->
+ forall n m a b, a<=n ->
+ testbit (bitwise op n a b) m = op (testbit a m) (testbit b m).
+Proof.
+ intros op Hop.
+ induction n; intros m a b Ha.
+ simpl. inversion Ha; subst. now rewrite testbit_0_l.
+ destruct m.
+ apply odd_bitwise.
+ unfold testbit; fold testbit. rewrite div2_bitwise.
+ apply IHn; now apply div2_decr.
+Qed.
+
+Lemma testbit_bitwise_2 : forall op, op false false = false ->
+ forall n m a b, a<=n -> b<=n ->
+ testbit (bitwise op n a b) m = op (testbit a m) (testbit b m).
+Proof.
+ intros op Hop.
+ induction n; intros m a b Ha Hb.
+ simpl. inversion Ha; inversion Hb; subst. now rewrite testbit_0_l.
+ destruct m.
+ apply odd_bitwise.
+ unfold testbit; fold testbit. rewrite div2_bitwise.
+ apply IHn; now apply div2_decr.
+Qed.
+
+Lemma land_spec : forall a b n,
+ testbit (land a b) n = testbit a n && testbit b n.
+Proof.
+ intros. unfold land. apply testbit_bitwise_1; trivial.
+Qed.
+
+Lemma ldiff_spec : forall a b n,
+ testbit (ldiff a b) n = testbit a n && negb (testbit b n).
+Proof.
+ intros. unfold ldiff. apply testbit_bitwise_1; trivial.
+Qed.
+
+Lemma lor_spec : forall a b n,
+ testbit (lor a b) n = testbit a n || testbit b n.
+Proof.
+ intros. unfold lor. apply testbit_bitwise_2. trivial.
+ destruct (le_ge_dec a b). now rewrite max_r. now rewrite max_l.
+ destruct (le_ge_dec a b). now rewrite max_r. now rewrite max_l.
+Qed.
+
+Lemma lxor_spec : forall a b n,
+ testbit (lxor a b) n = xorb (testbit a n) (testbit b n).
+Proof.
+ intros. unfold lxor. apply testbit_bitwise_2. trivial.
+ destruct (le_ge_dec a b). now rewrite max_r. now rewrite max_l.
+ destruct (le_ge_dec a b). now rewrite max_r. now rewrite max_l.
+Qed.
(** * Implementation of [NAxiomsSig] by [nat] *)
-Module NPeanoAxiomsMod <: NAxiomsSig.
+Module Nat
+ <: NAxiomsSig <: UsualDecidableTypeFull <: OrderedTypeFull <: TotalOrder.
(** Bi-directional induction. *)
@@ -40,6 +598,16 @@ Proof.
reflexivity.
Qed.
+Theorem one_succ : 1 = S 0.
+Proof.
+reflexivity.
+Qed.
+
+Theorem two_succ : 2 = S 1.
+Proof.
+reflexivity.
+Qed.
+
Theorem add_0_l : forall n : nat, 0 + n = n.
Proof.
reflexivity.
@@ -57,7 +625,7 @@ Qed.
Theorem sub_succ_r : forall n m : nat, n - (S m) = pred (n - m).
Proof.
-intros n m; induction n m using nat_double_ind; simpl; auto. apply sub_0_r.
+induction n; destruct m; simpl; auto. apply sub_0_r.
Qed.
Theorem mul_0_l : forall n : nat, 0 * n = 0.
@@ -67,49 +635,32 @@ Qed.
Theorem mul_succ_l : forall n m : nat, S n * m = n * m + m.
Proof.
-intros n m; now rewrite plus_comm.
+assert (add_S_r : forall n m, n+S m = S(n+m)) by (induction n; auto).
+assert (add_comm : forall n m, n+m = m+n).
+ induction n; simpl; auto. intros; rewrite add_S_r; auto.
+intros n m; now rewrite add_comm.
Qed.
(** Order on natural numbers *)
Program Instance lt_wd : Proper (eq==>eq==>iff) lt.
-Theorem lt_eq_cases : forall n m : nat, n <= m <-> n < m \/ n = m.
-Proof.
-intros n m; split.
-apply le_lt_or_eq.
-intro H; destruct H as [H | H].
-now apply lt_le_weak. rewrite H; apply le_refl.
-Qed.
-
-Theorem lt_irrefl : forall n : nat, ~ (n < n).
-Proof.
-exact lt_irrefl.
-Qed.
-
Theorem lt_succ_r : forall n m : nat, n < S m <-> n <= m.
Proof.
-intros n m; split; [apply lt_n_Sm_le | apply le_lt_n_Sm].
+unfold lt; split. apply le_S_n. induction 1; auto.
Qed.
-Theorem min_l : forall n m : nat, n <= m -> min n m = n.
-Proof.
-exact min_l.
-Qed.
-
-Theorem min_r : forall n m : nat, m <= n -> min n m = m.
-Proof.
-exact min_r.
-Qed.
-Theorem max_l : forall n m : nat, m <= n -> max n m = n.
+Theorem lt_eq_cases : forall n m : nat, n <= m <-> n < m \/ n = m.
Proof.
-exact max_l.
+split.
+inversion 1; auto. rewrite lt_succ_r; auto.
+destruct 1; [|subst; auto]. rewrite <- lt_succ_r; auto.
Qed.
-Theorem max_r : forall n m : nat, n <= m -> max n m = m.
+Theorem lt_irrefl : forall n : nat, ~ (n < n).
Proof.
-exact max_r.
+induction n. intro H; inversion H. rewrite lt_succ_r; auto.
Qed.
(** Facts specific to natural numbers, not integers. *)
@@ -119,25 +670,26 @@ Proof.
reflexivity.
Qed.
-Definition recursion (A : Type) : A -> (nat -> A -> A) -> nat -> A :=
+(** Recursion fonction *)
+
+Definition recursion {A} : A -> (nat -> A -> A) -> nat -> A :=
nat_rect (fun _ => A).
-Implicit Arguments recursion [A].
-Instance recursion_wd (A : Type) (Aeq : relation A) :
- Proper (Aeq ==> (eq==>Aeq==>Aeq) ==> eq ==> Aeq) (@recursion A).
+Instance recursion_wd {A} (Aeq : relation A) :
+ Proper (Aeq ==> (eq==>Aeq==>Aeq) ==> eq ==> Aeq) recursion.
Proof.
intros a a' Ha f f' Hf n n' Hn. subst n'.
induction n; simpl; auto. apply Hf; auto.
Qed.
Theorem recursion_0 :
- forall (A : Type) (a : A) (f : nat -> A -> A), recursion a f 0 = a.
+ forall {A} (a : A) (f : nat -> A -> A), recursion a f 0 = a.
Proof.
reflexivity.
Qed.
Theorem recursion_succ :
- forall (A : Type) (Aeq : relation A) (a : A) (f : nat -> A -> A),
+ forall {A} (Aeq : relation A) (a : A) (f : nat -> A -> A),
Aeq a a -> Proper (eq==>Aeq==>Aeq) f ->
forall n : nat, Aeq (recursion a f (S n)) (f n (recursion a f n)).
Proof.
@@ -149,7 +701,11 @@ Qed.
Definition t := nat.
Definition eq := @eq nat.
+Definition eqb := beq_nat.
+Definition compare := nat_compare.
Definition zero := 0.
+Definition one := 1.
+Definition two := 2.
Definition succ := S.
Definition pred := pred.
Definition add := plus.
@@ -157,81 +713,101 @@ Definition sub := minus.
Definition mul := mult.
Definition lt := lt.
Definition le := le.
+Definition ltb := ltb.
+Definition leb := leb.
+
Definition min := min.
Definition max := max.
-
-End NPeanoAxiomsMod.
-
-(** Now we apply the largest property functor *)
-
-Module Export NPeanoPropMod := NPropFunct NPeanoAxiomsMod.
-
-
-
-(** Euclidean Division *)
-
-Definition divF div x y := if leb y x then S (div (x-y) y) else 0.
-Definition modF mod x y := if leb y x then mod (x-y) y else x.
-Definition initF (_ _ : nat) := 0.
-
-Fixpoint loop {A} (F:A->A)(i:A) (n:nat) : A :=
- match n with
- | 0 => i
- | S n => F (loop F i n)
- end.
-
-Definition div x y := loop divF initF x x y.
-Definition modulo x y := loop modF initF x x y.
-Infix "/" := div : nat_scope.
-Infix "mod" := modulo (at level 40, no associativity) : nat_scope.
-
-Lemma div_mod : forall x y, y<>0 -> x = y*(x/y) + x mod y.
-Proof.
- cut (forall n x y, y<>0 -> x<=n ->
- x = y*(loop divF initF n x y) + (loop modF initF n x y)).
- intros H x y Hy. apply H; auto.
- induction n.
- simpl; unfold initF; simpl. intros. nzsimpl. auto with arith.
- simpl; unfold divF at 1, modF at 1.
- intros.
- destruct (leb y x) as [ ]_eqn:L;
- [apply leb_complete in L | apply leb_complete_conv in L].
- rewrite mul_succ_r, <- add_assoc, (add_comm y), add_assoc.
- rewrite <- IHn; auto.
- symmetry; apply sub_add; auto.
- rewrite <- NPeanoAxiomsMod.lt_succ_r.
- apply lt_le_trans with x; auto.
- apply lt_minus; auto. rewrite <- neq_0_lt_0; auto.
- nzsimpl; auto.
-Qed.
-
-Lemma mod_upper_bound : forall x y, y<>0 -> x mod y < y.
-Proof.
- cut (forall n x y, y<>0 -> x<=n -> loop modF initF n x y < y).
- intros H x y Hy. apply H; auto.
- induction n.
- simpl; unfold initF. intros. rewrite <- neq_0_lt_0; auto.
- simpl; unfold modF at 1.
- intros.
- destruct (leb y x) as [ ]_eqn:L;
- [apply leb_complete in L | apply leb_complete_conv in L]; auto.
- apply IHn; auto.
- rewrite <- NPeanoAxiomsMod.lt_succ_r.
- apply lt_le_trans with x; auto.
- apply lt_minus; auto. rewrite <- neq_0_lt_0; auto.
-Qed.
-
-Require Import NDiv.
-
-Module NDivMod <: NDivSig.
- Include NPeanoAxiomsMod.
- Definition div := div.
- Definition modulo := modulo.
- Definition div_mod := div_mod.
- Definition mod_upper_bound := mod_upper_bound.
- Local Obligation Tactic := simpl_relation.
- Program Instance div_wd : Proper (eq==>eq==>eq) div.
- Program Instance mod_wd : Proper (eq==>eq==>eq) modulo.
-End NDivMod.
-
-Module Export NDivPropMod := NDivPropFunct NDivMod NPeanoPropMod.
+Definition max_l := max_l.
+Definition max_r := max_r.
+Definition min_l := min_l.
+Definition min_r := min_r.
+
+Definition eqb_eq := beq_nat_true_iff.
+Definition compare_spec := nat_compare_spec.
+Definition eq_dec := eq_nat_dec.
+Definition leb_le := leb_le.
+Definition ltb_lt := ltb_lt.
+
+Definition Even := Even.
+Definition Odd := Odd.
+Definition even := even.
+Definition odd := odd.
+Definition even_spec := even_spec.
+Definition odd_spec := odd_spec.
+
+Program Instance pow_wd : Proper (eq==>eq==>eq) pow.
+Definition pow_0_r := pow_0_r.
+Definition pow_succ_r := pow_succ_r.
+Lemma pow_neg_r : forall a b, b<0 -> a^b = 0. inversion 1. Qed.
+Definition pow := pow.
+
+Definition square := square.
+Definition square_spec := square_spec.
+
+Definition log2_spec := log2_spec.
+Definition log2_nonpos := log2_nonpos.
+Definition log2 := log2.
+
+Definition sqrt_spec a (Ha:0<=a) := sqrt_spec a.
+Lemma sqrt_neg : forall a, a<0 -> sqrt a = 0. inversion 1. Qed.
+Definition sqrt := sqrt.
+
+Definition div := div.
+Definition modulo := modulo.
+Program Instance div_wd : Proper (eq==>eq==>eq) div.
+Program Instance mod_wd : Proper (eq==>eq==>eq) modulo.
+Definition div_mod := div_mod.
+Definition mod_bound_pos := mod_bound_pos.
+
+Definition divide := divide.
+Definition gcd := gcd.
+Definition gcd_divide_l := gcd_divide_l.
+Definition gcd_divide_r := gcd_divide_r.
+Definition gcd_greatest := gcd_greatest.
+Lemma gcd_nonneg : forall a b, 0<=gcd a b.
+Proof. intros. apply le_O_n. Qed.
+
+Definition testbit := testbit.
+Definition shiftl := shiftl.
+Definition shiftr := shiftr.
+Definition lxor := lxor.
+Definition land := land.
+Definition lor := lor.
+Definition ldiff := ldiff.
+Definition div2 := div2.
+
+Program Instance testbit_wd : Proper (eq==>eq==>Logic.eq) testbit.
+Definition testbit_odd_0 := testbit_odd_0.
+Definition testbit_even_0 := testbit_even_0.
+Definition testbit_odd_succ a n (_:0<=n) := testbit_odd_succ a n.
+Definition testbit_even_succ a n (_:0<=n) := testbit_even_succ a n.
+Lemma testbit_neg_r a n (H:n<0) : testbit a n = false.
+Proof. inversion H. Qed.
+Definition shiftl_spec_low := shiftl_spec_low.
+Definition shiftl_spec_high a n m (_:0<=m) := shiftl_spec_high a n m.
+Definition shiftr_spec a n m (_:0<=m) := shiftr_spec a n m.
+Definition lxor_spec := lxor_spec.
+Definition land_spec := land_spec.
+Definition lor_spec := lor_spec.
+Definition ldiff_spec := ldiff_spec.
+Definition div2_spec a : div2 a = shiftr a 1 := eq_refl _.
+
+(** Generic Properties *)
+
+Include NProp
+ <+ UsualMinMaxLogicalProperties <+ UsualMinMaxDecProperties.
+
+End Nat.
+
+(** [Nat] contains an [order] tactic for natural numbers *)
+
+(** Note that [Nat.order] is domain-agnostic: it will not prove
+ [1<=2] or [x<=x+x], but rather things like [x<=y -> y<=x -> x=y]. *)
+
+Section TestOrder.
+ Let test : forall x y, x<=y -> y<=x -> x=y.
+ Proof.
+ Nat.order.
+ Qed.
+End TestOrder.
diff --git a/theories/Numbers/Natural/SpecViaZ/NSig.v b/theories/Numbers/Natural/SpecViaZ/NSig.v
index 7893a82d..aaf44ca6 100644
--- a/theories/Numbers/Natural/SpecViaZ/NSig.v
+++ b/theories/Numbers/Natural/SpecViaZ/NSig.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,9 +8,7 @@
(* Benjamin Gregoire, Laurent Thery, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NSig.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Import ZArith Znumtheory.
+Require Import BinInt.
Open Scope Z_scope.
@@ -29,60 +27,83 @@ Module Type NType.
Parameter spec_pos: forall x, 0 <= [x].
Parameter of_N : N -> t.
- Parameter spec_of_N: forall x, to_Z (of_N x) = Z_of_N x.
- Definition to_N n := Zabs_N (to_Z n).
+ Parameter spec_of_N: forall x, to_Z (of_N x) = Z.of_N x.
+ Definition to_N n := Z.to_N (to_Z n).
Definition eq n m := [n] = [m].
Definition lt n m := [n] < [m].
Definition le n m := [n] <= [m].
Parameter compare : t -> t -> comparison.
- Parameter eq_bool : t -> t -> bool.
+ Parameter eqb : t -> t -> bool.
+ Parameter ltb : t -> t -> bool.
+ Parameter leb : t -> t -> bool.
Parameter max : t -> t -> t.
Parameter min : t -> t -> t.
Parameter zero : t.
Parameter one : t.
+ Parameter two : t.
Parameter succ : t -> t.
Parameter pred : t -> t.
Parameter add : t -> t -> t.
Parameter sub : t -> t -> t.
Parameter mul : t -> t -> t.
Parameter square : t -> t.
- Parameter power_pos : t -> positive -> t.
- Parameter power : t -> N -> t.
+ Parameter pow_pos : t -> positive -> t.
+ Parameter pow_N : t -> N -> t.
+ Parameter pow : t -> t -> t.
Parameter sqrt : t -> t.
+ Parameter log2 : t -> t.
Parameter div_eucl : t -> t -> t * t.
Parameter div : t -> t -> t.
Parameter modulo : t -> t -> t.
Parameter gcd : t -> t -> t.
+ Parameter even : t -> bool.
+ Parameter odd : t -> bool.
+ Parameter testbit : t -> t -> bool.
Parameter shiftr : t -> t -> t.
Parameter shiftl : t -> t -> t.
- Parameter is_even : t -> bool.
+ Parameter land : t -> t -> t.
+ Parameter lor : t -> t -> t.
+ Parameter ldiff : t -> t -> t.
+ Parameter lxor : t -> t -> t.
+ Parameter div2 : t -> t.
- Parameter spec_compare: forall x y, compare x y = Zcompare [x] [y].
- Parameter spec_eq_bool: forall x y, eq_bool x y = Zeq_bool [x] [y].
- Parameter spec_max : forall x y, [max x y] = Zmax [x] [y].
- Parameter spec_min : forall x y, [min x y] = Zmin [x] [y].
+ Parameter spec_compare: forall x y, compare x y = ([x] ?= [y]).
+ Parameter spec_eqb : forall x y, eqb x y = ([x] =? [y]).
+ Parameter spec_ltb : forall x y, ltb x y = ([x] <? [y]).
+ Parameter spec_leb : forall x y, leb x y = ([x] <=? [y]).
+ Parameter spec_max : forall x y, [max x y] = Z.max [x] [y].
+ Parameter spec_min : forall x y, [min x y] = Z.min [x] [y].
Parameter spec_0: [zero] = 0.
Parameter spec_1: [one] = 1.
+ Parameter spec_2: [two] = 2.
Parameter spec_succ: forall n, [succ n] = [n] + 1.
Parameter spec_add: forall x y, [add x y] = [x] + [y].
- Parameter spec_pred: forall x, [pred x] = Zmax 0 ([x] - 1).
- Parameter spec_sub: forall x y, [sub x y] = Zmax 0 ([x] - [y]).
+ Parameter spec_pred: forall x, [pred x] = Z.max 0 ([x] - 1).
+ Parameter spec_sub: forall x y, [sub x y] = Z.max 0 ([x] - [y]).
Parameter spec_mul: forall x y, [mul x y] = [x] * [y].
- Parameter spec_square: forall x, [square x] = [x] * [x].
- Parameter spec_power_pos: forall x n, [power_pos x n] = [x] ^ Zpos n.
- Parameter spec_power: forall x n, [power x n] = [x] ^ Z_of_N n.
- Parameter spec_sqrt: forall x, [sqrt x] ^ 2 <= [x] < ([sqrt x] + 1) ^ 2.
+ Parameter spec_square: forall x, [square x] = [x] * [x].
+ Parameter spec_pow_pos: forall x n, [pow_pos x n] = [x] ^ Zpos n.
+ Parameter spec_pow_N: forall x n, [pow_N x n] = [x] ^ Z.of_N n.
+ Parameter spec_pow: forall x n, [pow x n] = [x] ^ [n].
+ Parameter spec_sqrt: forall x, [sqrt x] = Z.sqrt [x].
+ Parameter spec_log2: forall x, [log2 x] = Z.log2 [x].
Parameter spec_div_eucl: forall x y,
- let (q,r) := div_eucl x y in ([q], [r]) = Zdiv_eucl [x] [y].
+ let (q,r) := div_eucl x y in ([q], [r]) = Z.div_eucl [x] [y].
Parameter spec_div: forall x y, [div x y] = [x] / [y].
Parameter spec_modulo: forall x y, [modulo x y] = [x] mod [y].
- Parameter spec_gcd: forall a b, [gcd a b] = Zgcd [a] [b].
- Parameter spec_shiftr: forall p x, [shiftr p x] = [x] / 2^[p].
- Parameter spec_shiftl: forall p x, [shiftl p x] = [x] * 2^[p].
- Parameter spec_is_even: forall x,
- if is_even x then [x] mod 2 = 0 else [x] mod 2 = 1.
+ Parameter spec_gcd: forall a b, [gcd a b] = Z.gcd [a] [b].
+ Parameter spec_even: forall x, even x = Z.even [x].
+ Parameter spec_odd: forall x, odd x = Z.odd [x].
+ Parameter spec_testbit: forall x p, testbit x p = Z.testbit [x] [p].
+ Parameter spec_shiftr: forall x p, [shiftr x p] = Z.shiftr [x] [p].
+ Parameter spec_shiftl: forall x p, [shiftl x p] = Z.shiftl [x] [p].
+ Parameter spec_land: forall x y, [land x y] = Z.land [x] [y].
+ Parameter spec_lor: forall x y, [lor x y] = Z.lor [x] [y].
+ Parameter spec_ldiff: forall x y, [ldiff x y] = Z.ldiff [x] [y].
+ Parameter spec_lxor: forall x y, [lxor x y] = Z.lxor [x] [y].
+ Parameter spec_div2: forall x, [div2 x] = Z.div2 [x].
End NType.
@@ -90,9 +111,12 @@ Module Type NType_Notation (Import N:NType).
Notation "[ x ]" := (to_Z x).
Infix "==" := eq (at level 70).
Notation "0" := zero.
+ Notation "1" := one.
+ Notation "2" := two.
Infix "+" := add.
Infix "-" := sub.
Infix "*" := mul.
+ Infix "^" := pow.
Infix "<=" := le.
Infix "<" := lt.
End NType_Notation.
diff --git a/theories/Numbers/Natural/SpecViaZ/NSigNAxioms.v b/theories/Numbers/Natural/SpecViaZ/NSigNAxioms.v
index a0e096be..2c7884ac 100644
--- a/theories/Numbers/Natural/SpecViaZ/NSigNAxioms.v
+++ b/theories/Numbers/Natural/SpecViaZ/NSigNAxioms.v
@@ -1,27 +1,28 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: NSigNAxioms.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Import ZArith Nnat NAxioms NDiv NSig.
+Require Import ZArith OrdersFacts Nnat NAxioms NSig.
(** * The interface [NSig.NType] implies the interface [NAxiomsSig] *)
-Module NTypeIsNAxioms (Import N : NType').
+Module NTypeIsNAxioms (Import NN : NType').
Hint Rewrite
- spec_0 spec_succ spec_add spec_mul spec_pred spec_sub
- spec_div spec_modulo spec_gcd spec_compare spec_eq_bool
- spec_max spec_min spec_power_pos spec_power
+ spec_0 spec_1 spec_2 spec_succ spec_add spec_mul spec_pred spec_sub
+ spec_div spec_modulo spec_gcd spec_compare spec_eqb spec_ltb spec_leb
+ spec_square spec_sqrt spec_log2 spec_max spec_min spec_pow_pos spec_pow_N
+ spec_pow spec_even spec_odd spec_testbit spec_shiftl spec_shiftr
+ spec_land spec_lor spec_ldiff spec_lxor spec_div2 spec_of_N
: nsimpl.
Ltac nsimpl := autorewrite with nsimpl.
-Ltac ncongruence := unfold eq; repeat red; intros; nsimpl; congruence.
-Ltac zify := unfold eq, lt, le in *; nsimpl.
+Ltac ncongruence := unfold eq, to_N; repeat red; intros; nsimpl; congruence.
+Ltac zify := unfold eq, lt, le, to_N in *; nsimpl.
+Ltac omega_pos n := generalize (spec_pos n); omega with *.
Local Obligation Tactic := ncongruence.
@@ -36,14 +37,29 @@ Program Instance mul_wd : Proper (eq==>eq==>eq) mul.
Theorem pred_succ : forall n, pred (succ n) == n.
Proof.
-intros. zify. generalize (spec_pos n); omega with *.
+intros. zify. omega_pos n.
Qed.
-Definition N_of_Z z := of_N (Zabs_N z).
+Theorem one_succ : 1 == succ 0.
+Proof.
+now zify.
+Qed.
+
+Theorem two_succ : 2 == succ 1.
+Proof.
+now zify.
+Qed.
+
+Definition N_of_Z z := of_N (Z.to_N z).
+
+Lemma spec_N_of_Z z : (0<=z)%Z -> [N_of_Z z] = z.
+Proof.
+ unfold N_of_Z. zify. apply Z2N.id.
+Qed.
Section Induction.
-Variable A : N.t -> Prop.
+Variable A : NN.t -> Prop.
Hypothesis A_wd : Proper (eq==>iff) A.
Hypothesis A0 : A 0.
Hypothesis AS : forall n, A n <-> A (succ n).
@@ -62,9 +78,7 @@ Proof.
intros z H1 H2.
unfold B in *. apply -> AS in H2.
setoid_replace (N_of_Z (z + 1)) with (succ (N_of_Z z)); auto.
-unfold eq. rewrite spec_succ.
-unfold N_of_Z.
-rewrite 2 spec_of_N, 2 Z_of_N_abs, 2 Zabs_eq; auto with zarith.
+unfold eq. rewrite spec_succ, 2 spec_N_of_Z; auto with zarith.
Qed.
Lemma B_holds : forall z : Z, (0 <= z)%Z -> B z.
@@ -76,9 +90,7 @@ Theorem bi_induction : forall n, A n.
Proof.
intro n. setoid_replace n with (N_of_Z (to_Z n)).
apply B_holds. apply spec_pos.
-red; unfold N_of_Z.
-rewrite spec_of_N, Z_of_N_abs, Zabs_eq; auto.
-apply spec_pos.
+red. now rewrite spec_N_of_Z by apply spec_pos.
Qed.
End Induction.
@@ -95,7 +107,7 @@ Qed.
Theorem sub_0_r : forall n, n - 0 == n.
Proof.
-intros. zify. generalize (spec_pos n); omega with *.
+intros. zify. omega_pos n.
Qed.
Theorem sub_succ_r : forall n m, n - (succ m) == pred (n - m).
@@ -115,39 +127,69 @@ Qed.
(** Order *)
-Lemma compare_spec : forall x y, CompSpec eq lt x y (compare x y).
+Lemma eqb_eq x y : eqb x y = true <-> x == y.
+Proof.
+ zify. apply Z.eqb_eq.
+Qed.
+
+Lemma leb_le x y : leb x y = true <-> x <= y.
+Proof.
+ zify. apply Z.leb_le.
+Qed.
+
+Lemma ltb_lt x y : ltb x y = true <-> x < y.
+Proof.
+ zify. apply Z.ltb_lt.
+Qed.
+
+Lemma compare_eq_iff n m : compare n m = Eq <-> n == m.
Proof.
- intros. zify. destruct (Zcompare_spec [x] [y]); auto.
+ intros. zify. apply Z.compare_eq_iff.
Qed.
-Definition eqb := eq_bool.
+Lemma compare_lt_iff n m : compare n m = Lt <-> n < m.
+Proof.
+ intros. zify. reflexivity.
+Qed.
-Lemma eqb_eq : forall x y, eq_bool x y = true <-> x == y.
+Lemma compare_le_iff n m : compare n m <> Gt <-> n <= m.
Proof.
- intros. zify. symmetry. apply Zeq_is_eq_bool.
+ intros. zify. reflexivity.
Qed.
+Lemma compare_antisym n m : compare m n = CompOpp (compare n m).
+Proof.
+ intros. zify. apply Z.compare_antisym.
+Qed.
+
+Include BoolOrderFacts NN NN NN [no inline].
+
Instance compare_wd : Proper (eq ==> eq ==> Logic.eq) compare.
Proof.
-intros x x' Hx y y' Hy. rewrite 2 spec_compare, Hx, Hy; intuition.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Instance lt_wd : Proper (eq ==> eq ==> iff) lt.
+Instance eqb_wd : Proper (eq ==> eq ==> Logic.eq) eqb.
Proof.
-intros x x' Hx y y' Hy; unfold lt; rewrite Hx, Hy; intuition.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Theorem lt_eq_cases : forall n m, n <= m <-> n < m \/ n == m.
+Instance ltb_wd : Proper (eq ==> eq ==> Logic.eq) ltb.
Proof.
-intros. zify. omega.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Theorem lt_irrefl : forall n, ~ n < n.
+Instance leb_wd : Proper (eq ==> eq ==> Logic.eq) leb.
Proof.
-intros. zify. omega.
+intros x x' Hx y y' Hy. zify. now rewrite Hx, Hy.
Qed.
-Theorem lt_succ_r : forall n m, n < (succ m) <-> n <= m.
+Instance lt_wd : Proper (eq ==> eq ==> iff) lt.
+Proof.
+intros x x' Hx y y' Hy; unfold lt; rewrite Hx, Hy; intuition.
+Qed.
+
+Theorem lt_succ_r : forall n m, n < succ m <-> n <= m.
Proof.
intros. zify. omega.
Qed.
@@ -179,6 +221,98 @@ Proof.
zify. auto.
Qed.
+(** Power *)
+
+Program Instance pow_wd : Proper (eq==>eq==>eq) pow.
+
+Lemma pow_0_r : forall a, a^0 == 1.
+Proof.
+ intros. now zify.
+Qed.
+
+Lemma pow_succ_r : forall a b, 0<=b -> a^(succ b) == a * a^b.
+Proof.
+ intros a b. zify. intros. now Z.nzsimpl.
+Qed.
+
+Lemma pow_neg_r : forall a b, b<0 -> a^b == 0.
+Proof.
+ intros a b. zify. intro Hb. exfalso. omega_pos b.
+Qed.
+
+Lemma pow_pow_N : forall a b, a^b == pow_N a (to_N b).
+Proof.
+ intros. zify. f_equal.
+ now rewrite Z2N.id by apply spec_pos.
+Qed.
+
+Lemma pow_N_pow : forall a b, pow_N a b == a^(of_N b).
+Proof.
+ intros. now zify.
+Qed.
+
+Lemma pow_pos_N : forall a p, pow_pos a p == pow_N a (Npos p).
+Proof.
+ intros. now zify.
+Qed.
+
+(** Square *)
+
+Lemma square_spec n : square n == n * n.
+Proof.
+ now zify.
+Qed.
+
+(** Sqrt *)
+
+Lemma sqrt_spec : forall n, 0<=n ->
+ (sqrt n)*(sqrt n) <= n /\ n < (succ (sqrt n))*(succ (sqrt n)).
+Proof.
+ intros n. zify. apply Z.sqrt_spec.
+Qed.
+
+Lemma sqrt_neg : forall n, n<0 -> sqrt n == 0.
+Proof.
+ intros n. zify. intro H. exfalso. omega_pos n.
+Qed.
+
+(** Log2 *)
+
+Lemma log2_spec : forall n, 0<n ->
+ 2^(log2 n) <= n /\ n < 2^(succ (log2 n)).
+Proof.
+ intros n. zify. change (Z.log2 [n]+1)%Z with (Z.succ (Z.log2 [n])).
+ apply Z.log2_spec.
+Qed.
+
+Lemma log2_nonpos : forall n, n<=0 -> log2 n == 0.
+Proof.
+ intros n. zify. apply Z.log2_nonpos.
+Qed.
+
+(** Even / Odd *)
+
+Definition Even n := exists m, n == 2*m.
+Definition Odd n := exists m, n == 2*m+1.
+
+Lemma even_spec n : even n = true <-> Even n.
+Proof.
+ unfold Even. zify. rewrite Z.even_spec.
+ split; intros (m,Hm).
+ - exists (N_of_Z m). zify. rewrite spec_N_of_Z; trivial. omega_pos n.
+ - exists [m]. revert Hm; now zify.
+Qed.
+
+Lemma odd_spec n : odd n = true <-> Odd n.
+Proof.
+ unfold Odd. zify. rewrite Z.odd_spec.
+ split; intros (m,Hm).
+ - exists (N_of_Z m). zify. rewrite spec_N_of_Z; trivial. omega_pos n.
+ - exists [m]. revert Hm; now zify.
+Qed.
+
+(** Div / Mod *)
+
Program Instance div_wd : Proper (eq==>eq==>eq) div.
Program Instance mod_wd : Proper (eq==>eq==>eq) modulo.
@@ -187,16 +321,131 @@ Proof.
intros a b. zify. intros. apply Z_div_mod_eq_full; auto.
Qed.
-Theorem mod_upper_bound : forall a b, ~b==0 -> modulo a b < b.
+Theorem mod_bound_pos : forall a b, 0<=a -> 0<b ->
+ 0 <= modulo a b /\ modulo a b < b.
+Proof.
+intros a b. zify. apply Z.mod_bound_pos.
+Qed.
+
+(** Gcd *)
+
+Definition divide n m := exists p, m == p*n.
+Local Notation "( x | y )" := (divide x y) (at level 0).
+
+Lemma spec_divide : forall n m, (n|m) <-> Z.divide [n] [m].
+Proof.
+ intros n m. split.
+ - intros (p,H). exists [p]. revert H; now zify.
+ - intros (z,H). exists (of_N (Z.abs_N z)). zify.
+ rewrite N2Z.inj_abs_N.
+ rewrite <- (Z.abs_eq [m]), <- (Z.abs_eq [n]) by apply spec_pos.
+ now rewrite H, Z.abs_mul.
+Qed.
+
+Lemma gcd_divide_l : forall n m, (gcd n m | n).
Proof.
-intros a b. zify. intros.
-destruct (Z_mod_lt [a] [b]); auto.
-generalize (spec_pos b); auto with zarith.
+ intros n m. apply spec_divide. zify. apply Z.gcd_divide_l.
Qed.
-Definition recursion (A : Type) (a : A) (f : N.t -> A -> A) (n : N.t) :=
- Nrect (fun _ => A) a (fun n a => f (N.of_N n) a) (N.to_N n).
-Implicit Arguments recursion [A].
+Lemma gcd_divide_r : forall n m, (gcd n m | m).
+Proof.
+ intros n m. apply spec_divide. zify. apply Z.gcd_divide_r.
+Qed.
+
+Lemma gcd_greatest : forall n m p, (p|n) -> (p|m) -> (p|gcd n m).
+Proof.
+ intros n m p. rewrite !spec_divide. zify. apply Z.gcd_greatest.
+Qed.
+
+Lemma gcd_nonneg : forall n m, 0 <= gcd n m.
+Proof.
+ intros. zify. apply Z.gcd_nonneg.
+Qed.
+
+(** Bitwise operations *)
+
+Program Instance testbit_wd : Proper (eq==>eq==>Logic.eq) testbit.
+
+Lemma testbit_odd_0 : forall a, testbit (2*a+1) 0 = true.
+Proof.
+ intros. zify. apply Z.testbit_odd_0.
+Qed.
+
+Lemma testbit_even_0 : forall a, testbit (2*a) 0 = false.
+Proof.
+ intros. zify. apply Z.testbit_even_0.
+Qed.
+
+Lemma testbit_odd_succ : forall a n, 0<=n ->
+ testbit (2*a+1) (succ n) = testbit a n.
+Proof.
+ intros a n. zify. apply Z.testbit_odd_succ.
+Qed.
+
+Lemma testbit_even_succ : forall a n, 0<=n ->
+ testbit (2*a) (succ n) = testbit a n.
+Proof.
+ intros a n. zify. apply Z.testbit_even_succ.
+Qed.
+
+Lemma testbit_neg_r : forall a n, n<0 -> testbit a n = false.
+Proof.
+ intros a n. zify. apply Z.testbit_neg_r.
+Qed.
+
+Lemma shiftr_spec : forall a n m, 0<=m ->
+ testbit (shiftr a n) m = testbit a (m+n).
+Proof.
+ intros a n m. zify. apply Z.shiftr_spec.
+Qed.
+
+Lemma shiftl_spec_high : forall a n m, 0<=m -> n<=m ->
+ testbit (shiftl a n) m = testbit a (m-n).
+Proof.
+ intros a n m. zify. intros Hn H. rewrite Z.max_r by auto with zarith.
+ now apply Z.shiftl_spec_high.
+Qed.
+
+Lemma shiftl_spec_low : forall a n m, m<n ->
+ testbit (shiftl a n) m = false.
+Proof.
+ intros a n m. zify. intros H. now apply Z.shiftl_spec_low.
+Qed.
+
+Lemma land_spec : forall a b n,
+ testbit (land a b) n = testbit a n && testbit b n.
+Proof.
+ intros a n m. zify. now apply Z.land_spec.
+Qed.
+
+Lemma lor_spec : forall a b n,
+ testbit (lor a b) n = testbit a n || testbit b n.
+Proof.
+ intros a n m. zify. now apply Z.lor_spec.
+Qed.
+
+Lemma ldiff_spec : forall a b n,
+ testbit (ldiff a b) n = testbit a n && negb (testbit b n).
+Proof.
+ intros a n m. zify. now apply Z.ldiff_spec.
+Qed.
+
+Lemma lxor_spec : forall a b n,
+ testbit (lxor a b) n = xorb (testbit a n) (testbit b n).
+Proof.
+ intros a n m. zify. now apply Z.lxor_spec.
+Qed.
+
+Lemma div2_spec : forall a, div2 a == shiftr a 1.
+Proof.
+ intros a. zify. now apply Z.div2_spec.
+Qed.
+
+(** Recursion *)
+
+Definition recursion (A : Type) (a : A) (f : NN.t -> A -> A) (n : NN.t) :=
+ Nrect (fun _ => A) a (fun n a => f (NN.of_N n) a) (NN.to_N n).
+Arguments recursion [A] a f n.
Instance recursion_wd (A : Type) (Aeq : relation A) :
Proper (Aeq ==> (eq==>Aeq==>Aeq) ==> eq ==> Aeq) (@recursion A).
@@ -204,53 +453,35 @@ Proof.
unfold eq.
intros a a' Eaa' f f' Eff' x x' Exx'.
unfold recursion.
-unfold N.to_N.
+unfold NN.to_N.
rewrite <- Exx'; clear x' Exx'.
-replace (Zabs_N [x]) with (N_of_nat (Zabs_nat [x])).
-induction (Zabs_nat [x]).
+induction (Z.to_N [x]) using N.peano_ind.
simpl; auto.
-rewrite N_of_S, 2 Nrect_step; auto. apply Eff'; auto.
-destruct [x]; simpl; auto.
-change (nat_of_P p) with (nat_of_N (Npos p)); apply N_of_nat_of_N.
-change (nat_of_P p) with (nat_of_N (Npos p)); apply N_of_nat_of_N.
+rewrite 2 Nrect_step. now apply Eff'.
Qed.
Theorem recursion_0 :
- forall (A : Type) (a : A) (f : N.t -> A -> A), recursion a f 0 = a.
+ forall (A : Type) (a : A) (f : NN.t -> A -> A), recursion a f 0 = a.
Proof.
-intros A a f; unfold recursion, N.to_N; rewrite N.spec_0; simpl; auto.
+intros A a f; unfold recursion, NN.to_N; rewrite NN.spec_0; simpl; auto.
Qed.
Theorem recursion_succ :
- forall (A : Type) (Aeq : relation A) (a : A) (f : N.t -> A -> A),
+ forall (A : Type) (Aeq : relation A) (a : A) (f : NN.t -> A -> A),
Aeq a a -> Proper (eq==>Aeq==>Aeq) f ->
forall n, Aeq (recursion a f (succ n)) (f n (recursion a f n)).
Proof.
-unfold N.eq, recursion; intros A Aeq a f EAaa f_wd n.
-replace (N.to_N (succ n)) with (Nsucc (N.to_N n)).
+unfold eq, recursion; intros A Aeq a f EAaa f_wd n.
+replace (to_N (succ n)) with (N.succ (to_N n)) by
+ (zify; now rewrite <- Z2N.inj_succ by apply spec_pos).
rewrite Nrect_step.
apply f_wd; auto.
-unfold N.to_N.
-rewrite N.spec_of_N, Z_of_N_abs, Zabs_eq; auto.
- apply N.spec_pos.
-
-fold (recursion a f n).
-apply recursion_wd; auto.
-red; auto.
-unfold N.to_N.
-
-rewrite N.spec_succ.
-change ([n]+1)%Z with (Zsucc [n]).
-apply Z_of_N_eq_rev.
-rewrite Z_of_N_succ.
-rewrite 2 Z_of_N_abs.
-rewrite 2 Zabs_eq; auto.
-generalize (spec_pos n); auto with zarith.
-apply spec_pos; auto.
+zify. now rewrite Z2N.id by apply spec_pos.
+fold (recursion a f n). apply recursion_wd; auto. red; auto.
Qed.
End NTypeIsNAxioms.
-Module NType_NAxioms (N : NType)
- <: NAxiomsSig <: NDivSig <: HasCompare N <: HasEqBool N <: HasMinMax N
- := N <+ NTypeIsNAxioms.
+Module NType_NAxioms (NN : NType)
+ <: NAxiomsSig <: OrderFunctions NN <: HasMinMax NN
+ := NN <+ NTypeIsNAxioms.
diff --git a/theories/Numbers/NumPrelude.v b/theories/Numbers/NumPrelude.v
index 124faba1..ba7859ee 100644
--- a/theories/Numbers/NumPrelude.v
+++ b/theories/Numbers/NumPrelude.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -8,132 +8,17 @@
(* Evgeny Makarov, INRIA, 2007 *)
(************************************************************************)
-(*i $Id: NumPrelude.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
-Require Export Setoid Morphisms.
+Require Export Setoid Morphisms Morphisms_Prop.
Set Implicit Arguments.
-(*
-Contents:
-- Coercion from bool to Prop
-- Extension of the tactics stepl and stepr
-- Extentional properties of predicates, relations and functions
- (well-definedness and equality)
-- Relations on cartesian product
-- Miscellaneous
-*)
-
-(** Coercion from bool to Prop *)
-
-(*Definition eq_bool := (@eq bool).*)
-
-(*Inductive eq_true : bool -> Prop := is_eq_true : eq_true true.*)
-(* This has been added to theories/Datatypes.v *)
-(*Coercion eq_true : bool >-> Sortclass.*)
-
-(*Theorem eq_true_unfold_pos : forall b : bool, b <-> b = true.
-Proof.
-intro b; split; intro H. now inversion H. now rewrite H.
-Qed.
-
-Theorem eq_true_unfold_neg : forall b : bool, ~ b <-> b = false.
-Proof.
-intros b; destruct b; simpl; rewrite eq_true_unfold_pos.
-split; intro H; [elim (H (refl_equal true)) | discriminate H].
-split; intro H; [reflexivity | discriminate].
-Qed.
-
-Theorem eq_true_or : forall b1 b2 : bool, b1 || b2 <-> b1 \/ b2.
-Proof.
-destruct b1; destruct b2; simpl; tauto.
-Qed.
-
-Theorem eq_true_and : forall b1 b2 : bool, b1 && b2 <-> b1 /\ b2.
-Proof.
-destruct b1; destruct b2; simpl; tauto.
-Qed.
-
-Theorem eq_true_neg : forall b : bool, negb b <-> ~ b.
-Proof.
-destruct b; simpl; rewrite eq_true_unfold_pos; rewrite eq_true_unfold_neg;
-split; now intro.
-Qed.
-
-Theorem eq_true_iff : forall b1 b2 : bool, b1 = b2 <-> (b1 <-> b2).
-Proof.
-intros b1 b2; split; intro H.
-now rewrite H.
-destruct b1; destruct b2; simpl; try reflexivity.
-apply -> eq_true_unfold_neg. rewrite H. now intro.
-symmetry; apply -> eq_true_unfold_neg. rewrite <- H; now intro.
-Qed.*)
-
-(** Extension of the tactics stepl and stepr to make them
-applicable to hypotheses *)
-
-Tactic Notation "stepl" constr(t1') "in" hyp(H) :=
-match (type of H) with
-| ?R ?t1 ?t2 =>
- let H1 := fresh in
- cut (R t1' t2); [clear H; intro H | stepl t1; [assumption |]]
-| _ => fail 1 ": the hypothesis" H "does not have the form (R t1 t2)"
-end.
-
-Tactic Notation "stepl" constr(t1') "in" hyp(H) "by" tactic(r) := stepl t1' in H; [| r].
-
-Tactic Notation "stepr" constr(t2') "in" hyp(H) :=
-match (type of H) with
-| ?R ?t1 ?t2 =>
- let H1 := fresh in
- cut (R t1 t2'); [clear H; intro H | stepr t2; [assumption |]]
-| _ => fail 1 ": the hypothesis" H "does not have the form (R t1 t2)"
-end.
-
-Tactic Notation "stepr" constr(t2') "in" hyp(H) "by" tactic(r) := stepr t2' in H; [| r].
-
-(** Predicates, relations, functions *)
-
-Definition predicate (A : Type) := A -> Prop.
-
-Instance well_founded_wd A :
- Proper (@relation_equivalence A ==> iff) (@well_founded A).
-Proof.
-intros R1 R2 H.
-split; intros WF a; induction (WF a) as [x _ WF']; constructor;
-intros y Ryx; apply WF'; destruct (H y x); auto.
-Qed.
-
-(** [solve_predicate_wd] solves the goal [Proper (?==>iff) P]
- for P consisting of morphisms and quantifiers *)
-
-Ltac solve_predicate_wd :=
-let x := fresh "x" in
-let y := fresh "y" in
-let H := fresh "H" in
- intros x y H; setoid_rewrite H; reflexivity.
-
-(** [solve_relation_wd] solves the goal [Proper (?==>?==>iff) R]
- for R consisting of morphisms and quantifiers *)
-
-Ltac solve_relation_wd :=
-let x1 := fresh "x" in
-let y1 := fresh "y" in
-let H1 := fresh "H" in
-let x2 := fresh "x" in
-let y2 := fresh "y" in
-let H2 := fresh "H" in
- intros x1 y1 H1 x2 y2 H2;
- rewrite H1; setoid_rewrite H2; reflexivity.
-(* The following tactic uses solve_predicate_wd to solve the goals
-relating to well-defidedness that are produced by applying induction.
+(* The following tactic uses solve_proper to solve the goals
+relating to well-definedness that are produced by applying induction.
We declare it to take the tactic that applies the induction theorem
and not the induction theorem itself because the tactic may, for
example, supply additional arguments, as does NZinduct_center in
NZBase.v *)
Ltac induction_maker n t :=
- try intros until n;
- pattern n; t; clear n;
- [solve_predicate_wd | ..].
+ try intros until n; pattern n; t; clear n; [solve_proper | ..].
diff --git a/theories/Numbers/Rational/BigQ/BigQ.v b/theories/Numbers/Rational/BigQ/BigQ.v
index 82190f94..424db5b7 100644
--- a/theories/Numbers/Rational/BigQ/BigQ.v
+++ b/theories/Numbers/Rational/BigQ/BigQ.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -35,47 +35,21 @@ End BigN_BigZ.
(** This allows to build [BigQ] out of [BigN] and [BigQ] via [QMake] *)
-Module BigQ <: QType <: OrderedTypeFull <: TotalOrder :=
- QMake.Make BigN BigZ BigN_BigZ <+ !QProperties <+ HasEqBool2Dec
- <+ !MinMaxLogicalProperties <+ !MinMaxDecProperties.
+Delimit Scope bigQ_scope with bigQ.
-(** Notations about [BigQ] *)
+Module BigQ <: QType <: OrderedTypeFull <: TotalOrder.
+ Include QMake.Make BigN BigZ BigN_BigZ [scope abstract_scope to bigQ_scope].
+ Bind Scope bigQ_scope with t t_.
+ Include !QProperties <+ HasEqBool2Dec
+ <+ !MinMaxLogicalProperties <+ !MinMaxDecProperties.
+End BigQ.
-Notation bigQ := BigQ.t.
+(** Notations about [BigQ] *)
-Delimit Scope bigQ_scope with bigQ.
-Bind Scope bigQ_scope with bigQ.
-Bind Scope bigQ_scope with BigQ.t.
-Bind Scope bigQ_scope with BigQ.t_.
-(* Bind Scope has no retroactive effect, let's declare scopes by hand. *)
-Arguments Scope BigQ.Qz [bigZ_scope].
-Arguments Scope BigQ.Qq [bigZ_scope bigN_scope].
-Arguments Scope BigQ.to_Q [bigQ_scope].
-Arguments Scope BigQ.red [bigQ_scope].
-Arguments Scope BigQ.opp [bigQ_scope].
-Arguments Scope BigQ.inv [bigQ_scope].
-Arguments Scope BigQ.square [bigQ_scope].
-Arguments Scope BigQ.add [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.sub [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.mul [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.div [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.eq [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.lt [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.le [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.eq [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.compare [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.min [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.max [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.eq_bool [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.power_pos [bigQ_scope positive_scope].
-Arguments Scope BigQ.power [bigQ_scope Z_scope].
-Arguments Scope BigQ.inv_norm [bigQ_scope].
-Arguments Scope BigQ.add_norm [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.sub_norm [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.mul_norm [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.div_norm [bigQ_scope bigQ_scope].
-Arguments Scope BigQ.power_norm [bigQ_scope bigQ_scope].
+Local Open Scope bigQ_scope.
+Notation bigQ := BigQ.t.
+Bind Scope bigQ_scope with bigQ BigQ.t BigQ.t_.
(** As in QArith, we use [#] to denote fractions *)
Notation "p # q" := (BigQ.Qq p q) (at level 55, no associativity) : bigQ_scope.
Local Notation "0" := BigQ.zero : bigQ_scope.
@@ -88,19 +62,17 @@ Infix "/" := BigQ.div : bigQ_scope.
Infix "^" := BigQ.power : bigQ_scope.
Infix "?=" := BigQ.compare : bigQ_scope.
Infix "==" := BigQ.eq : bigQ_scope.
-Notation "x != y" := (~x==y)%bigQ (at level 70, no associativity) : bigQ_scope.
+Notation "x != y" := (~x==y) (at level 70, no associativity) : bigQ_scope.
Infix "<" := BigQ.lt : bigQ_scope.
Infix "<=" := BigQ.le : bigQ_scope.
-Notation "x > y" := (BigQ.lt y x)(only parsing) : bigQ_scope.
-Notation "x >= y" := (BigQ.le y x)(only parsing) : bigQ_scope.
-Notation "x < y < z" := (x<y /\ y<z)%bigQ : bigQ_scope.
-Notation "x < y <= z" := (x<y /\ y<=z)%bigQ : bigQ_scope.
-Notation "x <= y < z" := (x<=y /\ y<z)%bigQ : bigQ_scope.
-Notation "x <= y <= z" := (x<=y /\ y<=z)%bigQ : bigQ_scope.
+Notation "x > y" := (BigQ.lt y x) (only parsing) : bigQ_scope.
+Notation "x >= y" := (BigQ.le y x) (only parsing) : bigQ_scope.
+Notation "x < y < z" := (x<y /\ y<z) : bigQ_scope.
+Notation "x < y <= z" := (x<y /\ y<=z) : bigQ_scope.
+Notation "x <= y < z" := (x<=y /\ y<z) : bigQ_scope.
+Notation "x <= y <= z" := (x<=y /\ y<=z) : bigQ_scope.
Notation "[ q ]" := (BigQ.to_Q q) : bigQ_scope.
-Local Open Scope bigQ_scope.
-
(** [BigQ] is a field *)
Lemma BigQfieldth :
diff --git a/theories/Numbers/Rational/BigQ/QMake.v b/theories/Numbers/Rational/BigQ/QMake.v
index 49e9d075..995fbb9e 100644
--- a/theories/Numbers/Rational/BigQ/QMake.v
+++ b/theories/Numbers/Rational/BigQ/QMake.v
@@ -1,6 +1,6 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
@@ -39,6 +39,8 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Definition t := t_.
+ Bind Scope abstract_scope with t t_.
+
(** Specification with respect to [QArith] *)
Local Open Scope Q_scope.
@@ -55,7 +57,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Definition to_Q (q: t) :=
match q with
| Qz x => Z.to_Z x # 1
- | Qq x y => if N.eq_bool y N.zero then 0
+ | Qq x y => if N.eqb y N.zero then 0
else Z.to_Z x # Z2P (N.to_Z y)
end.
@@ -66,26 +68,18 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Proof.
intros x; rewrite N.spec_0; generalize (N.spec_pos x). romega.
Qed.
-(*
- Lemma if_fun_commut : forall A B (f:A->B)(b:bool) a a',
- f (if b then a else a') = if b then f a else f a'.
- Proof. now destruct b. Qed.
- Lemma if_fun_commut' : forall A B C D (f:A->B)(b:{C}+{D}) a a',
- f (if b then a else a') = if b then f a else f a'.
- Proof. now destruct b. Qed.
-*)
+ Ltac destr_zcompare := case Z.compare_spec; intros ?H.
+
Ltac destr_eqb :=
match goal with
- | |- context [Z.eq_bool ?x ?y] =>
- rewrite (Z.spec_eq_bool x y);
- generalize (Zeq_bool_if (Z.to_Z x) (Z.to_Z y));
- case (Zeq_bool (Z.to_Z x) (Z.to_Z y));
+ | |- context [Z.eqb ?x ?y] =>
+ rewrite (Z.spec_eqb x y);
+ case (Z.eqb_spec (Z.to_Z x) (Z.to_Z y));
destr_eqb
- | |- context [N.eq_bool ?x ?y] =>
- rewrite (N.spec_eq_bool x y);
- generalize (Zeq_bool_if (N.to_Z x) (N.to_Z y));
- case (Zeq_bool (N.to_Z x) (N.to_Z y));
+ | |- context [N.eqb ?x ?y] =>
+ rewrite (N.spec_eqb x y);
+ case (Z.eqb_spec (N.to_Z x) (N.to_Z y));
[ | let H:=fresh "H" in
try (intro H;generalize (N_to_Z_pos _ H); clear H)];
destr_eqb
@@ -100,6 +94,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Z.spec_gcd N.spec_gcd Zgcd_Zabs Zgcd_1
spec_Z_of_N spec_Zabs_N
: nz.
+
Ltac nzsimpl := autorewrite with nz in *.
Ltac qsimpl := try red; unfold to_Q; simpl; intros;
@@ -143,13 +138,13 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
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
+ if N.eqb dy N.zero then Z.compare zx Z.zero
else Z.compare (Z.mul zx (Z_of_N dy)) ny
| Qq nx dx, Qz zy =>
- if N.eq_bool dx N.zero then Z.compare Z.zero zy
+ if N.eqb dx N.zero then Z.compare Z.zero zy
else Z.compare nx (Z.mul zy (Z_of_N dx))
| Qq nx dx, Qq ny dy =>
- match N.eq_bool dx N.zero, N.eq_bool dy N.zero with
+ match N.eqb dx N.zero, N.eqb dy N.zero with
| true, true => Eq
| true, false => Z.compare Z.zero ny
| false, true => Z.compare nx Z.zero
@@ -299,15 +294,15 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
match y with
| Qz zy => Qz (Z.add zx zy)
| Qq ny dy =>
- if N.eq_bool dy N.zero then x
+ if N.eqb dy N.zero then x
else Qq (Z.add (Z.mul zx (Z_of_N dy)) ny) dy
end
| Qq nx dx =>
- if N.eq_bool dx N.zero then y
+ if N.eqb dx N.zero then y
else match y with
| Qz zy => Qq (Z.add nx (Z.mul zy (Z_of_N dx))) dx
| Qq ny dy =>
- if N.eq_bool dy N.zero then x
+ if N.eqb dy N.zero then x
else
let n := Z.add (Z.mul nx (Z_of_N dy)) (Z.mul ny (Z_of_N dx)) in
let d := N.mul dx dy in
@@ -331,15 +326,15 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
match y with
| Qz zy => Qz (Z.add zx zy)
| Qq ny dy =>
- if N.eq_bool dy N.zero then x
+ if N.eqb dy N.zero then x
else norm (Z.add (Z.mul zx (Z_of_N dy)) ny) dy
end
| Qq nx dx =>
- if N.eq_bool dx N.zero then y
+ if N.eqb dx N.zero then y
else match y with
| Qz zy => norm (Z.add nx (Z.mul zy (Z_of_N dx))) dx
| Qq ny dy =>
- if N.eq_bool dy N.zero then x
+ if N.eqb dy N.zero then x
else
let n := Z.add (Z.mul nx (Z_of_N dy)) (Z.mul ny (Z_of_N dx)) in
let d := N.mul dx dy in
@@ -376,8 +371,8 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Proof.
intros [z | x y]; simpl.
rewrite Z.spec_opp; auto.
- match goal with |- context[N.eq_bool ?X ?Y] =>
- generalize (N.spec_eq_bool X Y); case N.eq_bool
+ match goal with |- context[N.eqb ?X ?Y] =>
+ generalize (N.spec_eqb X Y); case N.eqb
end; auto; rewrite N.spec_0.
rewrite Z.spec_opp; auto.
Qed.
@@ -427,26 +422,29 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
| Qq nx dx, Qq ny dy => Qq (Z.mul nx ny) (N.mul dx dy)
end.
+ Ltac nsubst :=
+ match goal with E : N.to_Z _ = _ |- _ => rewrite E in * end.
+
Theorem spec_mul : forall x y, [mul x y] == [x] * [y].
Proof.
intros [x | nx dx] [y | ny dy]; unfold Qmult; simpl; qsimpl.
rewrite Pmult_1_r, Z2P_correct; auto.
destruct (Zmult_integral (N.to_Z dx) (N.to_Z dy)); intuition.
- rewrite H0 in H1; auto with zarith.
- rewrite H0 in H1; auto with zarith.
- rewrite H in H1; nzsimpl; auto with zarith.
+ nsubst; auto with zarith.
+ nsubst; auto with zarith.
+ nsubst; nzsimpl; auto with zarith.
rewrite Zpos_mult_morphism, 2 Z2P_correct; auto.
Qed.
Definition norm_denum n d :=
- if N.eq_bool d N.one then Qz n else Qq n d.
+ if N.eqb d N.one then Qz n else Qq n d.
Lemma spec_norm_denum : forall n d,
[norm_denum n d] == [Qq n d].
Proof.
unfold norm_denum; intros; simpl; qsimpl.
congruence.
- rewrite H0 in *; auto with zarith.
+ nsubst; auto with zarith.
Qed.
Definition irred n d :=
@@ -526,7 +524,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Qed.
Definition mul_norm_Qz_Qq z n d :=
- if Z.eq_bool z Z.zero then zero
+ if Z.eqb z Z.zero then zero
else
let gcd := N.gcd (Zabs_N z) d in
match N.compare gcd N.one with
@@ -554,12 +552,12 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
intros z n d; unfold mul_norm_Qz_Qq; nzsimpl; rewrite Zcompare_gt.
destr_eqb; nzsimpl; intros Hz.
qsimpl; rewrite Hz; auto.
- destruct Z_le_gt_dec; intros.
+ destruct Z_le_gt_dec as [LE|GT].
qsimpl.
rewrite spec_norm_denum.
qsimpl.
- rewrite Zdiv_gcd_zero in z0; auto with zarith.
- rewrite H in *. rewrite Zdiv_0_l in *; discriminate.
+ rewrite Zdiv_gcd_zero in GT; auto with zarith.
+ nsubst. rewrite Zdiv_0_l in *; discriminate.
rewrite <- Zmult_assoc, (Zmult_comm (Z.to_Z n)), Zmult_assoc.
rewrite Zgcd_div_swap0; try romega.
ring.
@@ -635,13 +633,15 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
rewrite spec_norm_denum.
qsimpl.
- destruct (Zmult_integral _ _ H0) as [Eq|Eq].
+ match goal with E : (_ * _ = 0)%Z |- _ =>
+ destruct (Zmult_integral _ _ E) as [Eq|Eq] end.
rewrite Eq in *; simpl in *.
rewrite <- Hg2' in *; auto with zarith.
rewrite Eq in *; simpl in *.
rewrite <- Hg2 in *; auto with zarith.
- destruct (Zmult_integral _ _ H) as [Eq|Eq].
+ match goal with E : (_ * _ = 0)%Z |- _ =>
+ destruct (Zmult_integral _ _ E) as [Eq|Eq] end.
rewrite Hz' in Eq; rewrite Eq in *; auto with zarith.
rewrite Hz in Eq; rewrite Eq in *; auto with zarith.
@@ -689,13 +689,13 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
rewrite Zgcd_1_rel_prime in *.
apply bezout_rel_prime.
- destruct (rel_prime_bezout _ _ H4) as [u v Huv].
+ destruct (rel_prime_bezout (Z.to_Z ny) (N.to_Z dy)) as [u v Huv]; trivial.
apply Bezout_intro with (u*g')%Z (v*g)%Z.
rewrite <- Huv, <- Hg1', <- Hg2. ring.
rewrite Zgcd_1_rel_prime in *.
apply bezout_rel_prime.
- destruct (rel_prime_bezout _ _ H3) as [u v Huv].
+ destruct (rel_prime_bezout (Z.to_Z nx) (N.to_Z dx)) as [u v Huv]; trivial.
apply Bezout_intro with (u*g)%Z (v*g')%Z.
rewrite <- Huv, <- Hg2', <- Hg1. ring.
Qed.
@@ -753,10 +753,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
destr_eqb; nzsimpl; intros.
intros; rewrite Zabs_eq in *; romega.
intros; rewrite Zabs_eq in *; romega.
- clear H1.
- rewrite H0.
- compute; auto.
- clear H1.
+ nsubst; compute; auto.
set (n':=Z.to_Z n) in *; clearbody n'.
rewrite Zabs_eq by romega.
red; simpl.
@@ -768,9 +765,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
destr_eqb; nzsimpl; intros.
intros; rewrite Zabs_non_eq in *; romega.
intros; rewrite Zabs_non_eq in *; romega.
- clear H1.
- red; nzsimpl; rewrite H0; compute; auto.
- clear H1.
+ nsubst; compute; auto.
set (n':=Z.to_Z n) in *; clearbody n'.
red; simpl; nzsimpl.
rewrite Zabs_non_eq by romega.
@@ -789,7 +784,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
| Gt => Qq Z.minus_one (Zabs_N z)
end
| Qq n d =>
- if N.eq_bool d N.zero then zero else
+ if N.eqb d N.zero then zero else
match Z.compare Z.zero n with
| Eq => zero
| Lt =>
@@ -926,9 +921,9 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
destr_eqb; nzsimpl; intros.
apply Qeq_refl.
rewrite N.spec_square in *; nzsimpl.
- elim (Zmult_integral _ _ H0); romega.
- rewrite N.spec_square in *; nzsimpl.
- rewrite H in H0; romega.
+ match goal with E : (_ * _ = 0)%Z |- _ =>
+ elim (Zmult_integral _ _ E); romega end.
+ rewrite N.spec_square in *; nzsimpl; nsubst; romega.
rewrite Z.spec_square, N.spec_square.
red; simpl.
rewrite Zpos_mult_morphism; rewrite !Z2P_correct; auto.
@@ -937,8 +932,8 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
Definition power_pos (x : t) p : t :=
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)
+ | Qz zx => Qz (Z.pow_pos zx p)
+ | Qq nx dx => Qq (Z.pow_pos nx p) (N.pow_pos dx p)
end.
Theorem spec_power_pos : forall x p, [power_pos x p] == [x] ^ Zpos p.
@@ -946,25 +941,26 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
intros [ z | n d ] p; unfold power_pos.
(* Qz *)
simpl.
- rewrite Z.spec_power_pos.
+ rewrite Z.spec_pow_pos.
rewrite Qpower_decomp.
red; simpl; f_equal.
rewrite Zpower_pos_1_l; auto.
(* Qq *)
simpl.
- rewrite Z.spec_power_pos.
+ rewrite Z.spec_pow_pos.
destr_eqb; nzsimpl; intros.
apply Qeq_sym; apply Qpower_positive_0.
- rewrite N.spec_power_pos in *.
+ rewrite N.spec_pow_pos in *.
assert (0 < N.to_Z d ^ ' p)%Z by
(apply Zpower_gt_0; auto with zarith).
romega.
- rewrite N.spec_power_pos, H in *.
- rewrite Zpower_0_l in H0; [romega|discriminate].
+ exfalso.
+ rewrite N.spec_pow_pos in *. nsubst.
+ rewrite Zpower_0_l in *; [romega|discriminate].
rewrite Qpower_decomp.
red; simpl; do 3 f_equal.
rewrite Z2P_correct by (generalize (N.spec_pos d); romega).
- rewrite N.spec_power_pos. auto.
+ rewrite N.spec_pow_pos. auto.
Qed.
Instance strong_spec_power_pos x p `(Reduced x) : Reduced (power_pos x p).
@@ -979,10 +975,11 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
revert H.
unfold Reduced; rewrite strong_spec_red, Qred_iff; simpl.
destr_eqb; nzsimpl; simpl; intros.
- rewrite N.spec_power_pos in H0.
- rewrite H, Zpower_0_l in *; [romega|discriminate].
+ exfalso.
+ rewrite N.spec_pow_pos in *. nsubst.
+ rewrite Zpower_0_l in *; [romega|discriminate].
rewrite Z2P_correct in *; auto.
- rewrite N.spec_power_pos, Z.spec_power_pos; auto.
+ rewrite N.spec_pow_pos, Z.spec_pow_pos; auto.
rewrite Zgcd_1_rel_prime in *.
apply rel_prime_Zpower; auto with zarith.
Qed.
@@ -1274,7 +1271,7 @@ Module Make (N:NType)(Z:ZType)(Import NZ:NType_ZType N Z) <: QType.
apply Qred_complete; apply spec_power_pos; auto.
induction p using Pind.
simpl; ring.
- rewrite nat_of_P_succ_morphism; simpl Qcpower.
+ rewrite Psucc_S; simpl Qcpower.
rewrite <- IHp; clear IHp.
unfold Qcmult, Q2Qc.
apply Qc_decomp; intros _ _; unfold this.
diff --git a/theories/Numbers/Rational/SpecViaQ/QSig.v b/theories/Numbers/Rational/SpecViaQ/QSig.v
index 0fea26df..29e1e795 100644
--- a/theories/Numbers/Rational/SpecViaQ/QSig.v
+++ b/theories/Numbers/Rational/SpecViaQ/QSig.v
@@ -1,13 +1,11 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2010 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
-(*i $Id: QSig.v 14641 2011-11-06 11:59:10Z herbelin $ i*)
-
Require Import QArith Qpower Qminmax Orders RelationPairs GenericMinMax.
Open Scope Q_scope.
@@ -117,7 +115,7 @@ Ltac solve_wd2 := intros x x' Hx y y' Hy; qify; now rewrite Hx, Hy.
Local Obligation Tactic := solve_wd2 || solve_wd1.
Instance : Measure to_Q.
-Instance eq_equiv : Equivalence eq.
+Instance eq_equiv : Equivalence eq := {}.
Program Instance lt_wd : Proper (eq==>eq==>iff) lt.
Program Instance le_wd : Proper (eq==>eq==>iff) le.
@@ -137,13 +135,13 @@ Program Instance power_wd : Proper (eq==>Logic.eq==>eq) power.
(** Let's implement [HasCompare] *)
-Lemma compare_spec : forall x y, CompSpec eq lt x y (compare x y).
+Lemma compare_spec : forall x y, CompareSpec (x==y) (x<y) (y<x) (compare x y).
Proof. intros. qify. destruct (Qcompare_spec [x] [y]); auto. Qed.
(** Let's implement [TotalOrder] *)
Definition lt_compat := lt_wd.
-Instance lt_strorder : StrictOrder lt.
+Instance lt_strorder : StrictOrder lt := {}.
Lemma le_lteq : forall x y, x<=y <-> x<y \/ x==y.
Proof. intros. qify. apply Qle_lteq. Qed.
@@ -222,4 +220,4 @@ End QProperties.
Module QTypeExt (Q : QType)
<: QType <: TotalOrder <: HasCompare Q <: HasMinMax Q <: HasEqBool Q
- := Q <+ QProperties. \ No newline at end of file
+ := Q <+ QProperties.
diff --git a/theories/Numbers/vo.itarget b/theories/Numbers/vo.itarget
index 175a15e9..c69af03f 100644
--- a/theories/Numbers/vo.itarget
+++ b/theories/Numbers/vo.itarget
@@ -1,3 +1,4 @@
+BinNums.vo
BigNumPrelude.vo
Cyclic/Abstract/CyclicAxioms.vo
Cyclic/Abstract/NZCyclic.vo
@@ -23,10 +24,16 @@ Integer/Abstract/ZLt.vo
Integer/Abstract/ZMulOrder.vo
Integer/Abstract/ZMul.vo
Integer/Abstract/ZSgnAbs.vo
-Integer/Abstract/ZProperties.vo
Integer/Abstract/ZDivFloor.vo
Integer/Abstract/ZDivTrunc.vo
Integer/Abstract/ZDivEucl.vo
+Integer/Abstract/ZMaxMin.vo
+Integer/Abstract/ZParity.vo
+Integer/Abstract/ZPow.vo
+Integer/Abstract/ZGcd.vo
+Integer/Abstract/ZLcm.vo
+Integer/Abstract/ZBits.vo
+Integer/Abstract/ZProperties.vo
Integer/BigZ/BigZ.vo
Integer/BigZ/ZMake.vo
Integer/Binary/ZBinary.vo
@@ -43,7 +50,13 @@ NatInt/NZMul.vo
NatInt/NZOrder.vo
NatInt/NZProperties.vo
NatInt/NZDomain.vo
+NatInt/NZParity.vo
NatInt/NZDiv.vo
+NatInt/NZPow.vo
+NatInt/NZSqrt.vo
+NatInt/NZLog.vo
+NatInt/NZGcd.vo
+NatInt/NZBits.vo
Natural/Abstract/NAddOrder.vo
Natural/Abstract/NAdd.vo
Natural/Abstract/NAxioms.vo
@@ -56,6 +69,14 @@ Natural/Abstract/NStrongRec.vo
Natural/Abstract/NSub.vo
Natural/Abstract/NProperties.vo
Natural/Abstract/NDiv.vo
+Natural/Abstract/NMaxMin.vo
+Natural/Abstract/NParity.vo
+Natural/Abstract/NPow.vo
+Natural/Abstract/NSqrt.vo
+Natural/Abstract/NLog.vo
+Natural/Abstract/NGcd.vo
+Natural/Abstract/NLcm.vo
+Natural/Abstract/NBits.vo
Natural/BigN/BigN.vo
Natural/BigN/Nbasic.vo
Natural/BigN/NMake_gen.vo