diff options
author | letouzey <letouzey@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2011-05-05 15:12:23 +0000 |
---|---|---|
committer | letouzey <letouzey@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2011-05-05 15:12:23 +0000 |
commit | 157bee13827f9a616b6c82be4af110c8f2464c64 (patch) | |
tree | 5b51be276e4671c04f817b2706176c2b14921cad /theories/NArith/BinNat.v | |
parent | 74352a7bbfe536f43d73b4b6cec75252d2eb39e8 (diff) |
Modularization of BinNat + fixes of stdlib
A sub-module N in BinNat now contains functions add (ex-Nplus),
mul (ex-Nmult), ... and properties.
In particular, this sub-module N directly instantiates NAxiomsSig
and includes all derived properties NProp.
Files Ndiv_def and co are now obsolete and kept only for compat
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@14100 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'theories/NArith/BinNat.v')
-rw-r--r-- | theories/NArith/BinNat.v | 1402 |
1 files changed, 1073 insertions, 329 deletions
diff --git a/theories/NArith/BinNat.v b/theories/NArith/BinNat.v index 3a4250566..b1d62d776 100644 --- a/theories/NArith/BinNat.v +++ b/theories/NArith/BinNat.v @@ -7,7 +7,8 @@ (************************************************************************) Require Export BinNums. -Require Import BinPos. +Require Import BinPos RelationClasses Morphisms Setoid + Equalities GenericMinMax Wf_nat Bool NAxioms NProperties. (**********************************************************************) (** * Binary natural numbers, operations and properties *) @@ -16,25 +17,35 @@ Require Import BinPos. (** The type [N] and its constructors [N0] and [Npos] are now defined in [BinNums.v] *) +(** Every definitions and early properties about binary natural numbers + are placed in a module [N] for qualification purpose. *) + Local Open Scope N_scope. -Definition Ndiscr : forall n:N, { p:positive | n = Npos p } + { n = N0 }. -Proof. - destruct n; auto. - left; exists p; auto. -Defined. +(** Every definitions and early properties about positive numbers + are placed in a module [N] for qualification purpose. *) + +Module N + <: NAxiomsMiniSig + <: UsualOrderedTypeFull + <: UsualDecidableTypeFull + <: TotalOrder. + +Definition t := N. +Definition eq := @Logic.eq t. +Definition eq_equiv := @eq_equivalence t. -(** Operation x -> 2*x+1 *) +(** Operation [x -> 2*x+1] *) -Definition Ndouble_plus_one x := +Definition succ_double x := match x with | 0 => Npos 1 | Npos p => Npos p~1 end. -(** Operation x -> 2*x *) +(** Operation [x -> 2*x] *) -Definition Ndouble n := +Definition double n := match n with | 0 => 0 | Npos p => Npos p~0 @@ -42,88 +53,68 @@ Definition Ndouble n := (** Successor *) -Definition Nsucc n := +Definition succ n := match n with - | 0 => Npos 1 - | Npos p => Npos (Psucc p) + | 0 => 1 + | Npos p => Npos (Pos.succ p) end. (** Predecessor *) -Definition Npred (n : N) := match n with -| 0 => 0 -| Npos p => match p with - | xH => 0 - | _ => Npos (Ppred p) - end -end. +Definition pred n := + match n with + | 0 => 0 + | Npos p => Pos.pred_N p + end. (** The successor of a N can be seen as a positive *) -Definition Nsucc_pos (n : N) : positive := +Definition succ_pos (n : N) : positive := match n with | N0 => 1%positive - | Npos p => Psucc p + | Npos p => Pos.succ p end. -(** Similarly, the predecessor of a positive, seen as a N *) - -Definition Ppred_N (p:positive) : N := - match p with - | 1 => N0 - | p~1 => Npos (p~0) - | p~0 => Npos (Pdouble_minus_one p) - end%positive. - (** Addition *) -Definition Nplus n m := +Definition add n m := match n, m with | 0, _ => m | _, 0 => n | Npos p, Npos q => Npos (p + q) end. -Infix "+" := Nplus : N_scope. +Infix "+" := add : N_scope. (** Subtraction *) -Definition Nminus (n m : N) := +Definition sub n m := match n, m with | 0, _ => 0 | n, 0 => n | Npos n', Npos m' => - match Pminus_mask n' m' with + match Pos.sub_mask n' m' with | IsPos p => Npos p | _ => 0 end end. -Infix "-" := Nminus : N_scope. +Infix "-" := sub : N_scope. (** Multiplication *) -Definition Nmult n m := +Definition mul n m := match n, m with | 0, _ => 0 | _, 0 => 0 | Npos p, Npos q => Npos (p * q) end. -Infix "*" := Nmult : N_scope. - -(** Boolean Equality *) - -Definition Neqb n m := - match n, m with - | 0, 0 => true - | Npos n, Npos m => Peqb n m - | _,_ => false - end. +Infix "*" := mul : N_scope. (** Order *) -Definition Ncompare n m := +Definition compare n m := match n, m with | 0, 0 => Eq | 0, Npos m' => Lt @@ -131,64 +122,299 @@ Definition Ncompare n m := | Npos n', Npos m' => (n' ?= m')%positive end. -Infix "?=" := Ncompare (at level 70, no associativity) : N_scope. +Infix "?=" := compare (at level 70, no associativity) : N_scope. -Definition Nlt (x y:N) := (x ?= y) = Lt. -Definition Ngt (x y:N) := (x ?= y) = Gt. -Definition Nle (x y:N) := (x ?= y) <> Gt. -Definition Nge (x y:N) := (x ?= y) <> Lt. +Definition lt x y := (x ?= y) = Lt. +Definition gt x y := (x ?= y) = Gt. +Definition le x y := (x ?= y) <> Gt. +Definition ge x y := (x ?= y) <> Lt. -Infix "<=" := Nle : N_scope. -Infix "<" := Nlt : N_scope. -Infix ">=" := Nge : N_scope. -Infix ">" := Ngt : N_scope. +Infix "<=" := le : N_scope. +Infix "<" := lt : N_scope. +Infix ">=" := ge : N_scope. +Infix ">" := gt : N_scope. Notation "x <= y <= z" := (x <= y /\ y <= z) : N_scope. Notation "x <= y < z" := (x <= y /\ y < z) : N_scope. Notation "x < y < z" := (x < y /\ y < z) : N_scope. Notation "x < y <= z" := (x < y /\ y <= z) : N_scope. +(** Boolean equality and comparison *) + +(** Nota: this [eqb] is not convertible with the generated [N_beq], + since the underlying [Pos.eqb] differs from [positive_beq] + (cf BinIntDef). *) + +Fixpoint eqb n m := + match n, m with + | 0, 0 => true + | Npos p, Npos q => Pos.eqb p q + | _, _ => false + end. + +Definition leb x y := + match x ?= y with Gt => false | _ => true end. + +Definition ltb x y := + match x ?= y with Lt => true | _ => false end. + +Infix "=?" := eqb (at level 70, no associativity) : N_scope. +Infix "<=?" := leb (at level 70, no associativity) : N_scope. +Infix "<?" := ltb (at level 70, no associativity) : N_scope. + (** Min and max *) -Definition Nmin (n n' : N) := match Ncompare n n' with +Definition min n n' := match n ?= n' with | Lt | Eq => n | Gt => n' end. -Definition Nmax (n n' : N) := match Ncompare n n' with +Definition max n n' := match n ?= n' with | Lt | Eq => n' | Gt => n end. +(** Dividing by 2 *) + +Definition div2 n := + match n with + | 0 => 0 + | Npos 1 => 0 + | Npos (p~0) => Npos p + | Npos (p~1) => Npos p + end. + +(** Parity *) + +Definition even n := + match n with + | 0 => true + | Npos (xO _) => true + | _ => false + end. + +Definition odd n := negb (even n). + +(** Power *) + +Definition pow n p := + match p, n with + | 0, _ => Npos 1 + | _, 0 => 0 + | Npos p, Npos q => Npos (q^p) + end. + +Infix "^" := pow : N_scope. + +(** Base-2 logarithm *) + +Definition log2 n := + match n with + | 0 => 0 + | Npos 1 => 0 + | Npos (p~0) => Npos (Pos.size p) + | Npos (p~1) => Npos (Pos.size p) + end. + +(** How many digits in a number ? + Number 0 is said to have no digits at all. +*) + +Definition size n := + match n with + | 0 => 0 + | Npos p => Npos (Pos.size p) + end. + +Definition size_nat n := + match n with + | 0 => O + | Npos p => Pos.size_nat p + end. + +(** Euclidean division *) + +Fixpoint pos_div_eucl (a:positive)(b:N) : N * N := + match a with + | xH => + match b with 1 => (1,0) | _ => (0,1) end + | xO a' => + let (q, r) := pos_div_eucl a' b in + let r' := double r in + if b <=? r' then (succ_double q, r' - b) + else (double q, r') + | xI a' => + let (q, r) := pos_div_eucl a' b in + let r' := succ_double r in + if b <=? r' then (succ_double q, r' - b) + else (double q, r') + end. + +Definition div_eucl (a b:N) : N * N := + match a, b with + | 0, _ => (0, 0) + | _, 0 => (0, a) + | Npos na, _ => pos_div_eucl na b + end. + +Definition div a b := fst (div_eucl a b). +Definition modulo a b := snd (div_eucl a b). + +Infix "/" := div : N_scope. +Infix "mod" := modulo (at level 40, no associativity) : N_scope. + +(** Greatest common divisor *) + +Definition divide p q := exists r, p*r = q. + +Notation "( p | q )" := (divide p q) (at level 0) : N_scope. + +Definition gcd a b := + match a, b with + | 0, _ => b + | _, 0 => a + | Npos p, Npos q => Npos (Pos.gcd p q) + end. + +(** Generalized Gcd, also computing rests of [a] and [b] after + division by gcd. *) + +Definition ggcd a b := + match a, b with + | 0, _ => (b,(0,1)) + | _, 0 => (a,(1,0)) + | Npos p, Npos q => + let '(g,(aa,bb)) := Pos.ggcd p q in + (Npos g, (Npos aa, Npos bb)) + end. + +(** Square root *) + +Definition sqrtrem n := + match n with + | 0 => (0, 0) + | Npos p => + match Pos.sqrtrem p with + | (s, IsPos r) => (Npos s, Npos r) + | (s, _) => (Npos s, 0) + end + end. + +Definition sqrt n := + match n with + | 0 => 0 + | Npos p => Npos (Pos.sqrt p) + end. + +(** Operation over bits of a [N] number. *) + +(** Logical [or] *) + +Definition lor n m := + match n, m with + | 0, _ => m + | _, 0 => n + | Npos p, Npos q => Npos (Pos.lor p q) + end. + +(** Logical [and] *) + +Definition land n m := + match n, m with + | 0, _ => 0 + | _, 0 => 0 + | Npos p, Npos q => Pos.land p q + end. + +(** Logical [diff] *) + +Fixpoint ldiff n m := + match n, m with + | 0, _ => 0 + | _, 0 => n + | Npos p, Npos q => Pos.ldiff p q + end. + +(** [xor] *) + +Definition lxor n m := + match n, m with + | 0, _ => m + | _, 0 => n + | Npos p, Npos q => Pos.lxor p q + end. + +(** Shifts *) + +Definition shiftl_nat (a:N)(n:nat) := iter_nat n _ double a. + +Definition shiftr_nat (a:N)(n:nat) := iter_nat n _ div2 a. + +Definition shiftl a n := + match a with + | 0 => 0 + | Npos a => Npos (Pos.shiftl a n) + end. + +Definition shiftr a n := + match n with + | 0 => a + | Npos p => Pos.iter p div2 a + end. + +(** Checking whether a particular bit is set or not *) + +Definition testbit_nat (a:N) := + match a with + | 0 => fun _ => false + | Npos p => Pos.testbit_nat p + end. + +(** Same, but with index in N *) + +Definition testbit a n := + match a with + | 0 => false + | Npos p => Pos.testbit p n + end. + (** Translation from [N] to [nat] and back. *) -Definition nat_of_N (a:N) := +Definition to_nat (a:N) := match a with | N0 => O - | Npos p => nat_of_P p + | Npos p => Pos.to_nat p end. -Definition N_of_nat (n:nat) := +Definition of_nat (n:nat) := match n with | O => 0 - | S n' => Npos (P_of_succ_nat n') + | S n' => Npos (Pos.of_succ_nat n') end. (** Decidability of equality. *) -Definition N_eq_dec : forall n m : N, { n = m } + { n <> m }. +Definition eq_dec : forall n m : N, { n = m } + { n <> m }. Proof. decide equality. - apply positive_eq_dec. + apply Pos.eq_dec. Defined. -(** convenient induction principles *) +(** Discrimination principle *) -Lemma N_ind_double : +Definition discr n : { p:positive | n = Npos p } + { n = N0 }. +Proof. + destruct n; auto. + left; exists p; auto. +Defined. + +(** Convenient induction principles *) + +Lemma binary_ind : forall (a:N) (P:N -> Prop), P 0 -> - (forall a, P a -> P (Ndouble a)) -> - (forall a, P a -> P (Ndouble_plus_one a)) -> P a. + (forall a, P a -> P (double a)) -> + (forall a, P a -> P (succ_double a)) -> P a. Proof. intros a P P0 P2 PS2. destruct a as [|p]. trivial. induction p as [p IHp|p IHp| ]. @@ -197,11 +423,11 @@ Proof. now apply (PS2 0). Qed. -Lemma N_rec_double : +Lemma binary_rec : forall (a:N) (P:N -> Set), P 0 -> - (forall a, P a -> P (Ndouble a)) -> - (forall a, P a -> P (Ndouble_plus_one a)) -> P a. + (forall a, P a -> P (double a)) -> + (forall a, P a -> P (succ_double a)) -> P a. Proof. intros a P P0 P2 PS2. destruct a as [|p]. trivial. induction p as [p IHp|p IHp| ]. @@ -212,478 +438,996 @@ Qed. (** Peano induction on binary natural numbers *) -Definition Nrect +Definition peano_rect (P : N -> Type) (a : P 0) - (f : forall n : N, P n -> P (Nsucc n)) (n : N) : P n := + (f : forall n : N, P n -> P (succ n)) (n : N) : P n := let f' (p : positive) (x : P (Npos p)) := f (Npos p) x in let P' (p : positive) := P (Npos p) in match n return (P n) with | 0 => a -| Npos p => Prect P' (f 0 a) f' p +| Npos p => Pos.peano_rect P' (f 0 a) f' p end. -Theorem Nrect_base : forall P a f, Nrect P a f 0 = a. +Theorem peano_rect_base P a f : peano_rect P a f 0 = a. Proof. -intros P a f; simpl; reflexivity. +reflexivity. Qed. -Theorem Nrect_step : forall P a f n, Nrect P a f (Nsucc n) = f n (Nrect P a f n). +Theorem peano_rect_succ P a f n : + peano_rect P a f (succ n) = f n (peano_rect P a f n). Proof. -intros P a f; destruct n as [| p]; simpl; -[rewrite Prect_base | rewrite Prect_succ]; reflexivity. +destruct n; simpl; +[rewrite Pos.peano_rect_base | rewrite Pos.peano_rect_succ]; reflexivity. Qed. -Definition Nind (P : N -> Prop) := Nrect P. +Definition peano_ind (P : N -> Prop) := peano_rect P. -Definition Nrec (P : N -> Set) := Nrect P. +Definition peano_rec (P : N -> Set) := peano_rect P. -Theorem Nrec_base : forall P a f, Nrec P a f 0 = a. +Theorem peano_rec_base P a f : peano_rec P a f 0 = a. Proof. -intros P a f; unfold Nrec; apply Nrect_base. +apply peano_rect_base. Qed. -Theorem Nrec_step : forall P a f n, Nrec P a f (Nsucc n) = f n (Nrec P a f n). +Theorem peano_rec_succ P a f n : + peano_rec P a f (succ n) = f n (peano_rec P a f n). Proof. -intros P a f; unfold Nrec; apply Nrect_step. +apply peano_rect_succ. Qed. -(** Properties of successor and predecessor *) +(** Properties of double *) -Theorem Npred_succ : forall n : N, Npred (Nsucc n) = n. +Lemma double_spec n : double n = 2 * n. Proof. -intros [| p]; simpl. reflexivity. -case_eq (Psucc p); try (intros q H; rewrite <- H; now rewrite Ppred_succ). -intro H; false_hyp H Psucc_not_one. -Qed. - -Theorem Npred_minus : forall n, Npred n = Nminus n (Npos 1). -Proof. - intros [|[p|p|]]; trivial. + reflexivity. Qed. -Lemma Nsucc_pred : forall n, n<>0 -> Nsucc (Npred n) = n. +Lemma succ_double_spec n : succ_double n = 2 * n + 1. Proof. - intros [|n] H; (now destruct H) || clear H. - rewrite Npred_minus. simpl. destruct n; simpl; trivial. - f_equal; apply Psucc_o_double_minus_one_eq_xO. + now destruct n. Qed. (** Properties of mixed successor and predecessor. *) -Lemma Ppred_N_spec : forall p, Ppred_N p = Npred (Npos p). +Lemma pos_pred_spec p : Pos.pred_N p = pred (Npos p). Proof. now destruct p. Qed. -Lemma Nsucc_pos_spec : forall n, Npos (Nsucc_pos n) = Nsucc n. +Lemma succ_pos_spec n : Npos (succ_pos n) = succ n. Proof. now destruct n. Qed. -Lemma Ppred_Nsucc : forall n, Ppred_N (Nsucc_pos n) = n. +Lemma pos_pred_succ n : Pos.pred_N (succ_pos n) = n. Proof. - intros. now rewrite Ppred_N_spec, Nsucc_pos_spec, Npred_succ. + destruct n. trivial. apply Pos.pred_N_succ. Qed. -(** Properties of addition *) - -Theorem Nplus_0_l : forall n:N, 0 + n = n. +Lemma succ_pos_pred p : succ (Pos.pred_N p) = Npos p. Proof. -reflexivity. + destruct p; simpl; trivial. f_equal. apply Pos.succ_pred_double. Qed. -Theorem Nplus_0_r : forall n:N, n + 0 = n. +(** Properties of successor and predecessor *) + +Theorem pred_succ n : pred (succ n) = n. Proof. -destruct n; reflexivity. +destruct n; trivial. simpl. apply Pos.pred_N_succ. Qed. -Theorem Nplus_comm : forall n m:N, n + m = m + n. +Theorem pred_sub n : pred n = sub n 1. Proof. -intros. -destruct n; destruct m; simpl; try reflexivity. -rewrite Pplus_comm; reflexivity. + now destruct n as [|[p|p|]]. Qed. -Theorem Nplus_assoc : forall n m p:N, n + (m + p) = n + m + p. +Theorem succ_0_discr n : succ n <> 0. Proof. -intros. -destruct n; try reflexivity. -destruct m; try reflexivity. -destruct p; try reflexivity. -simpl; rewrite Pplus_assoc; reflexivity. +now destruct n. Qed. -Theorem Nplus_succ : forall n m:N, Nsucc n + m = Nsucc (n + m). +(** Specification of addition *) + +Theorem add_0_l n : 0 + n = n. Proof. -destruct n, m. - simpl; reflexivity. - unfold Nsucc, Nplus; rewrite <- Pplus_one_succ_l; reflexivity. - simpl; reflexivity. - simpl; rewrite Pplus_succ_permute_l; reflexivity. +reflexivity. Qed. -Theorem Nsucc_0 : forall n : N, Nsucc n <> 0. +Theorem add_succ_l n m : succ n + m = succ (n + m). Proof. -now destruct n. +destruct n, m; unfold succ, add; now rewrite ?Pos.add_1_l, ?Pos.add_succ_l. Qed. -Theorem Nsucc_inj : forall n m:N, Nsucc n = Nsucc m -> n = m. +(** Specification of subtraction. *) + +Theorem sub_0_r n : n - 0 = n. Proof. -intros [|p] [|q] H; simpl in *; trivial; injection H; clear H; intro H. - now elim (Psucc_not_one q). - now elim (Psucc_not_one p). - apply Psucc_inj in H. now f_equal. +now destruct n. Qed. -Theorem Nplus_reg_l : forall n m p:N, n + m = n + p -> m = p. +Theorem sub_succ_r n m : n - succ m = pred (n - m). Proof. - induction n using Nind. - trivial. - intros m p H; rewrite 2 Nplus_succ in H. - apply Nsucc_inj in H. now apply IHn. +destruct n as [|p], m as [|q]; trivial. +now destruct p. +simpl. rewrite Pos.sub_mask_succ_r, Pos.sub_mask_carry_spec. +now destruct (Pos.sub_mask p q) as [|[r|r|]|]. Qed. -(** Properties of subtraction. *) +(** Specification of multiplication *) -Lemma Nminus_N0_Nle : forall n n' : N, n - n' = 0 <-> n <= n'. +Theorem mul_0_l n : 0 * n = 0. Proof. -intros [| p] [| q]; unfold Nle; simpl; -split; intro H; try easy. -now elim H. -contradict H. now destruct (Pminus_mask_Gt _ _ H) as (h & -> & _). -destruct (Pcompare_spec p q); try now elim H. -subst. now rewrite Pminus_mask_diag. -now rewrite Pminus_mask_Lt. +reflexivity. Qed. -Theorem Nminus_0_r : forall n : N, n - 0 = n. +Theorem mul_succ_l n m : (succ n) * m = n * m + m. Proof. -now destruct n. +destruct n, m; simpl; trivial. f_equal. rewrite Pos.add_comm. +apply Pos.mul_succ_l. Qed. -Theorem Nminus_succ_r : forall n m : N, n - (Nsucc m) = Npred (n - m). +(** Properties of comparison *) + +Lemma compare_refl n : (n ?= n) = Eq. Proof. -intros [|p] [|q]; trivial. -now destruct p. -simpl. rewrite Pminus_mask_succ_r, Pminus_mask_carry_spec. -now destruct (Pminus_mask p q) as [|[r|r|]|]. +destruct n; simpl; trivial. apply Pos.compare_refl. Qed. -(** Properties of multiplication *) +Theorem compare_eq n m : (n ?= m) = Eq -> n = m. +Proof. +destruct n, m; simpl; try easy. intros. f_equal. +now apply Pos.compare_eq. +Qed. -Theorem Nmult_0_l : forall n:N, 0 * n = 0. +Theorem compare_eq_iff n m : (n ?= m) = Eq <-> n = m. Proof. -reflexivity. +split; intros. now apply compare_eq. subst; now apply compare_refl. Qed. -Theorem Nmult_1_l : forall n:N, Npos 1 * n = n. +Lemma compare_antisym n m : CompOpp (n ?= m) = (m ?= n). Proof. -destruct n; reflexivity. +destruct n, m; simpl; trivial. +symmetry. apply Pos.compare_antisym. (* TODO : quel sens ? *) Qed. -Theorem Nmult_Sn_m : forall n m : N, (Nsucc n) * m = m + n * m. +(** Specification of lt and le *) + +Theorem lt_irrefl n : ~ n < n. Proof. -intros [|n] [|m]; simpl; trivial. now rewrite Pmult_Sn_m. +unfold lt. now rewrite compare_refl. Qed. -Theorem Nmult_1_r : forall n:N, n * Npos 1%positive = n. +Lemma lt_eq_cases n m : n <= m <-> n < m \/ n=m. Proof. -intros [|n]; simpl; trivial. now rewrite Pmult_1_r. +unfold le, lt. rewrite <- compare_eq_iff. +destruct (n ?= m); now intuition. Qed. -Theorem Nmult_comm : forall n m:N, n * m = m * n. +Lemma lt_succ_r n m : n < succ m <-> n<=m. Proof. -intros [|n] [|m]; simpl; trivial. now rewrite Pmult_comm. +destruct n as [|p], m as [|q]; simpl; try easy'. +split. now destruct p. now destruct 1. +apply Pos.lt_succ_r. Qed. -Theorem Nmult_assoc : forall n m p:N, n * (m * p) = n * m * p. +Lemma compare_spec n m : CompareSpec (n=m) (n<m) (m<n) (n ?= m). Proof. -intros. -destruct n; try reflexivity. -destruct m; try reflexivity. -destruct p; try reflexivity. -simpl; rewrite Pmult_assoc; reflexivity. +case_eq (n ?= m); intro H; constructor; trivial. +now apply compare_eq. +red. now rewrite <- compare_antisym, H. Qed. -Theorem Nmult_plus_distr_r : forall n m p:N, (n + m) * p = n * p + m * p. +(** Properties of boolean comparisons. *) + +Lemma eqb_eq n m : eqb n m = true <-> n=m. Proof. -intros. -destruct n; try reflexivity. -destruct m; destruct p; try reflexivity. -simpl; rewrite Pmult_plus_distr_r; reflexivity. +destruct n as [|n], m as [|m]; simpl; try easy'. +rewrite Pos.eqb_eq. split; intro H. now subst. now destr_eq H. Qed. -Theorem Nmult_plus_distr_l : forall n m p:N, p * (n + m) = p * n + p * m. +Lemma ltb_lt n m : (n <? m) = true <-> n < m. Proof. -intros. rewrite ! (Nmult_comm p); apply Nmult_plus_distr_r. + unfold ltb, lt. destruct compare; easy'. Qed. -Theorem Nmult_reg_r : forall n m p:N, p <> 0 -> n * p = m * p -> n = m. +Lemma leb_le n m : (n <=? m) = true <-> n <= m. Proof. -destruct p; intros Hp H. -contradiction Hp; reflexivity. -destruct n; destruct m; reflexivity || (try discriminate H). -injection H; clear H; intro H; rewrite Pmult_reg_r with (1 := H); reflexivity. + unfold leb, le. destruct compare; easy'. Qed. -(** Properties of boolean order. *) +Lemma leb_spec n m : BoolSpec (n<=m) (m<n) (n <=? m). +Proof. + unfold le, lt, leb. rewrite <- (compare_antisym n m). + case compare; now constructor. +Qed. -Lemma Neqb_eq : forall n m, Neqb n m = true <-> n=m. +Lemma ltb_spec n m : BoolSpec (n<m) (m<=n) (n <? m). Proof. -destruct n as [|n], m as [|m]; simpl; split; auto; try discriminate. -intros; f_equal. apply (Peqb_eq n m); auto. -intros. apply (Peqb_eq n m). congruence. + unfold le, lt, ltb. rewrite <- (compare_antisym n m). + case compare; now constructor. Qed. -(** Properties of comparison *) +(** We regroup here some results used for proving the correctness + of more advanced functions. These results will also be provided + by the generic functor of properties about natural numbers + instantiated at the end of the file. *) + +Module Import BootStrap. -Lemma Nle_0 : forall n, 0<=n. +Theorem succ_inj n m : succ n = succ m -> n = m. Proof. - now destruct n. +destruct n as [|p], m as [|q]; intro H; simpl in *; trivial; destr_eq H. + now destruct (Pos.succ_not_1 q). + now destruct (Pos.succ_not_1 p). + f_equal. now apply Pos.succ_inj. Qed. -Lemma Ncompare_refl : forall n, (n ?= n) = Eq. +Theorem add_0_r n : n + 0 = n. Proof. -destruct n; simpl; auto. -apply Pcompare_refl. +now destruct n. Qed. -Theorem Ncompare_Eq_eq : forall n m:N, (n ?= m) = Eq -> n = m. +Theorem add_comm n m : n + m = m + n. Proof. -destruct n as [| n]; destruct m as [| m]; simpl; intro H; - reflexivity || (try discriminate H). - rewrite (Pcompare_Eq_eq n m H); reflexivity. +destruct n, m; simpl; try reflexivity. simpl. f_equal. apply Pos.add_comm. Qed. -Theorem Ncompare_eq_correct : forall n m:N, (n ?= m) = Eq <-> n = m. +Theorem add_assoc n m p : n + (m + p) = n + m + p. Proof. -split; intros; - [ apply Ncompare_Eq_eq; auto | subst; apply Ncompare_refl ]. +destruct n; try reflexivity. +destruct m; try reflexivity. +destruct p; try reflexivity. +simpl. f_equal. apply Pos.add_assoc. Qed. -Lemma Ncompare_antisym : forall n m, CompOpp (n ?= m) = (m ?= n). +Lemma sub_add n m : n <= m -> m - n + n = m. Proof. -destruct n; destruct m; simpl; auto. -exact (Pcompare_antisym p p0 Eq). + destruct n as [|p], m as [|q]; simpl; try easy'. + unfold le, compare. rewrite Pos.compare_antisym. intros H. + assert (H1 := Pos.sub_mask_compare q p). + assert (H2 := Pos.sub_mask_add q p). + destruct Pos.sub_mask as [|r|]; simpl in *; f_equal. + symmetry. now apply Pos.compare_eq. + rewrite Pos.add_comm. now apply H2. + rewrite <- H1 in H. now destruct H. Qed. -Lemma Ngt_Nlt : forall n m, n > m -> m < n. +Theorem mul_1_l n : 1 * n = n. Proof. -unfold Ngt, Nlt; intros n m GT. -rewrite <- Ncompare_antisym, GT; reflexivity. +now destruct n. Qed. -Theorem Nlt_irrefl : forall n : N, ~ n < n. +Theorem mul_comm n m : n * m = m * n. Proof. -intro n; unfold Nlt; now rewrite Ncompare_refl. +destruct n, m; simpl; trivial. f_equal. apply Pos.mul_comm. Qed. -Theorem Nlt_trans : forall n m q, n < m -> m < q -> n < q. +Theorem mul_assoc n m p : n * (m * p) = n * m * p. Proof. -destruct n; - destruct m; try discriminate; - destruct q; try discriminate; auto. -eapply Plt_trans; eauto. +destruct n; try reflexivity. +destruct m; try reflexivity. +destruct p; try reflexivity. +simpl. f_equal. apply Pos.mul_assoc. Qed. -Theorem Nlt_not_eq : forall n m, n < m -> ~ n = m. +Theorem mul_add_distr_r n m p : (n + m) * p = n * p + m * p. Proof. - intros n m LT EQ. subst m. elim (Nlt_irrefl n); auto. +destruct n; try reflexivity. +destruct m, p; try reflexivity. +simpl. f_equal. apply Pos.mul_add_distr_r. Qed. -Theorem Ncompare_n_Sm : - forall n m : N, (n ?= Nsucc m) = Lt <-> (n ?= m) = Lt \/ n = m. +Theorem mul_add_distr_l n m p : n * (m + p) = n * m + n * p. Proof. -intros [|p] [|q]; simpl; split; intros H; auto. -destruct p; discriminate. -destruct H; discriminate. -apply Plt_succ_r, Ple_lteq in H. destruct H; subst; auto. -apply Plt_succ_r, Ple_lteq. destruct H; [left|right]; congruence. +rewrite !(mul_comm n); apply mul_add_distr_r. Qed. -Lemma Nle_lteq : forall x y, x <= y <-> x < y \/ x=y. +Lemma le_0_l n : 0<=n. Proof. -unfold Nle, Nlt; intros. -generalize (Ncompare_eq_correct x y). -destruct (x ?= y); intuition; discriminate. +now destruct n. Qed. -Lemma Nlt_succ_r : forall n m, n < Nsucc m <-> n<=m. +Theorem lt_trans n m q : n < m -> m < q -> n < q. Proof. -intros n m. -eapply iff_trans. apply Ncompare_n_Sm. apply iff_sym, Nle_lteq. +destruct n, m, q; try easy. eapply Pos.lt_trans; eauto. Qed. -Lemma Nle_trans : forall n m p, n<=m -> m<=p -> n<=p. +Lemma le_trans n m p : n<=m -> m<=p -> n<=p. Proof. - intros n m p H H'. - apply Nle_lteq. apply Nle_lteq in H. apply Nle_lteq in H'. - destruct H, H'; subst; auto. - left; now apply Nlt_trans with m. + rewrite 3 lt_eq_cases. intros [H|H] [H'|H']; subst; + (now right) || left; trivial. + now apply lt_trans with m. Qed. -Lemma Nle_succ_l : forall n m, Nsucc n <= m <-> n < m. +Lemma add_lt_cancel_l n m p : p+n < p+m -> n<m. Proof. - intros. - unfold Nle, Nlt. - rewrite <- 2 (Ncompare_antisym m). - generalize (Nlt_succ_r m n). unfold Nle,Nlt. - destruct Ncompare, Ncompare; simpl; intros (U,V); - intuition; now try discriminate V. + intro H. destruct p. simpl; auto. + destruct n; destruct m. + elim (lt_irrefl _ H). + red; auto. + rewrite add_0_r in H. simpl in H. + red in H. simpl in H. + elim (Pos.lt_not_add_l _ _ H). + now apply (Pos.add_lt_mono_l p). Qed. -Lemma Ncompare_spec : forall x y, CompareSpec (x=y) (x<y) (y<x) (x ?= y). +End BootStrap. + +(** Specification of minimum and maximum *) + +Theorem min_l n m : n <= m -> min n m = n. Proof. -intros. -destruct (Ncompare x y) as [ ]_eqn; constructor; auto. -apply Ncompare_Eq_eq; auto. -apply Ngt_Nlt; auto. +unfold min, le. case compare; trivial. now destruct 1. Qed. -(** Order and operations *) +Theorem min_r n m : m <= n -> min n m = m. +Proof. +unfold min, le. rewrite <- compare_antisym. +case compare_spec; trivial. now destruct 2. +Qed. -(** NB : Many more results will come from NBinary, the Number instantiation. - The next lemmas are useful for proving the correctness of - advanced functions. -*) +Theorem max_l n m : m <= n -> max n m = n. +Proof. +unfold max, le. rewrite <- compare_antisym. +case compare_spec; auto. now destruct 2. +Qed. -Lemma Nplus_lt_cancel_l : forall n m p, p+n < p+m -> n<m. +Theorem max_r n m : n <= m -> max n m = m. Proof. - intros. destruct p. simpl; auto. - destruct n; destruct m. - elim (Nlt_irrefl _ H). - red; auto. - rewrite Nplus_0_r in H. simpl in H. - red in H. simpl in H. - elim (Plt_not_plus_l _ _ H). - now apply (Pplus_lt_mono_l p). +unfold max, le. case compare; trivial. now destruct 1. Qed. (** 0 is the least natural number *) -Theorem Ncompare_0 : forall n : N, Ncompare n 0 <> Lt. +Theorem compare_0_r n : (n ?= 0) <> Lt. Proof. -destruct n; discriminate. +now destruct n. Qed. (** Dividing by 2 *) -Definition Ndiv2 (n:N) := - match n with - | 0 => 0 - | Npos 1 => 0 - | Npos (p~0) => Npos p - | Npos (p~1) => Npos p - end. - -Lemma Ndouble_div2 : forall n:N, Ndiv2 (Ndouble n) = n. +Lemma div2_double n : div2 (double n) = n. Proof. - destruct n; trivial. +now destruct n. Qed. -Lemma Ndouble_plus_one_div2 : - forall n:N, Ndiv2 (Ndouble_plus_one n) = n. +Lemma div2_succ_double n : div2 (succ_double n) = n. Proof. - destruct n; trivial. +now destruct n. Qed. -Lemma Ndouble_inj : forall n m, Ndouble n = Ndouble m -> n = m. +Lemma double_inj n m : double n = double m -> n = m. Proof. - intros. rewrite <- (Ndouble_div2 n). rewrite H. apply Ndouble_div2. +intro H. rewrite <- (div2_double n), H. apply div2_double. Qed. -Lemma Ndouble_plus_one_inj : - forall n m, Ndouble_plus_one n = Ndouble_plus_one m -> n = m. +Lemma succ_double_inj n m : succ_double n = succ_double m -> n = m. Proof. - intros. rewrite <- (Ndouble_plus_one_div2 n). rewrite H. apply Ndouble_plus_one_div2. +intro H. rewrite <- (div2_succ_double n), H. apply div2_succ_double. Qed. -(** Power *) - -Definition Npow n p := - match p, n with - | 0, _ => Npos 1 - | _, 0 => 0 - | Npos p, Npos q => Npos (Ppow q p) - end. - -Infix "^" := Npow : N_scope. +(** Speficications of power *) -Lemma Npow_0_r : forall n, n ^ 0 = Npos 1. +Lemma pow_0_r n : n ^ 0 = 1. Proof. reflexivity. Qed. -Lemma Npow_succ_r : forall n p, n^(Nsucc p) = n * n^p. +Lemma pow_succ_r n p : 0<=p -> n^(succ p) = n * n^p. Proof. - intros [|q] [|p]; simpl; trivial; f_equal. - apply Ppow_succ_r. + intros _. + destruct n, p; simpl; trivial; f_equal. apply Pos.pow_succ_r. Qed. -(** Base-2 logarithm *) +Lemma pow_neg_r n p : p<0 -> n^p = 0. +Proof. + now destruct p. +Qed. -Definition Nlog2 n := - match n with - | 0 => 0 - | Npos 1 => 0 - | Npos (p~0) => Npos (Psize_pos p) - | Npos (p~1) => Npos (Psize_pos p) - end. +(** Specification of Base-2 logarithm *) -Lemma Nlog2_spec : forall n, 0 < n -> - (Npos 2)^(Nlog2 n) <= n < (Npos 2)^(Nsucc (Nlog2 n)). +Lemma log2_spec n : 0 < n -> + 2^(log2 n) <= n < 2^(succ (log2 n)). Proof. - intros [|[p|p|]] H; discriminate H || clear H; simpl; split. - eapply Nle_trans with (Npos (p~0)). - apply Psize_pos_le. - apply Nle_lteq; left. exact (Pcompare_p_Sp (p~0)). - apply Psize_pos_gt. - apply Psize_pos_le. - apply Psize_pos_gt. + destruct n as [|[p|p|]]; discriminate || intros _; simpl; split. + eapply le_trans with (Npos (p~0)). + apply Pos.size_le. + apply lt_eq_cases; left. apply Pos.lt_succ_diag_r. + apply Pos.size_gt. + apply Pos.size_le. + apply Pos.size_gt. discriminate. reflexivity. Qed. -Lemma Nlog2_nonpos : forall n, n<=0 -> Nlog2 n = 0. +Lemma log2_nonpos n : n<=0 -> log2 n = 0. Proof. - intros [|n] Hn. reflexivity. now destruct Hn. + destruct n; intros Hn. reflexivity. now destruct Hn. Qed. -(** Parity *) +Lemma size_log2 n : n<>0 -> size n = succ (log2 n). +Proof. + destruct n as [|[n|n| ]]; trivial. now destruct 1. +Qed. -Definition Neven n := - match n with - | 0 => true - | Npos (xO _) => true - | _ => false - end. -Definition Nodd n := negb (Neven n). +Lemma size_gt n : n < 2^(size n). +Proof. + destruct n. reflexivity. simpl. apply Pos.size_gt. +Qed. -Lemma Neven_spec : forall n, Neven n = true <-> exists m, n=2*m. +Lemma size_le n : 2^(size n) <= succ_double n. +Proof. + destruct n. discriminate. + simpl. apply le_trans with (Npos (p~0)). + apply Pos.size_le. + apply lt_eq_cases. left. apply Pos.lt_succ_diag_r. +Qed. + +(** Specification of parity functions *) + +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. destruct n. split. now exists 0. trivial. - destruct p; simpl; split; trivial; try discriminate. + destruct p; simpl; split; try easy. intros (m,H). now destruct m. now exists (Npos p). intros (m,H). now destruct m. Qed. -Lemma Nodd_spec : forall n, Nodd n = true <-> exists m, n=2*m+1. +Lemma odd_spec n : odd n = true <-> Odd n. Proof. destruct n. split. discriminate. intros (m,H). now destruct m. - destruct p; simpl; split; trivial; try discriminate. - exists (Npos p). reflexivity. + destruct p; simpl; split; try easy. + now exists (Npos p). intros (m,H). now destruct m. - exists 0. reflexivity. + now exists 0. +Qed. + +(** Specification of the euclidean division *) + +Theorem pos_div_eucl_spec (a:positive)(b:N) : + let (q,r) := pos_div_eucl a b in Npos a = q * b + r. +Proof. + induction a; cbv beta iota delta [pos_div_eucl]; fold pos_div_eucl; cbv zeta. + (* a~1 *) + destruct pos_div_eucl as (q,r). + assert (Npos a~1 = (double q)*b + succ_double r). + rewrite succ_double_spec, double_spec. + now rewrite add_assoc, <- mul_assoc, <- mul_add_distr_l, <- IHa. + case leb_spec; intros H'; trivial. + rewrite (succ_double_spec q), mul_add_distr_r, <- double_spec, + mul_1_l, <- add_assoc. + now rewrite (add_comm b), sub_add. + (* a~0 *) + destruct pos_div_eucl as (q,r). + assert (Npos a~0 = (double q)*b + double r). + rewrite (double_spec q), (double_spec r). (* BUG: !double_spec *) + now rewrite <- mul_assoc, <- mul_add_distr_l, <- IHa. + case leb_spec; intros H'; trivial. + rewrite (succ_double_spec q), mul_add_distr_r, <- double_spec, + mul_1_l, <- add_assoc. + now rewrite (add_comm b), sub_add. + (* 1 *) + now destruct b as [|[ | | ]]. +Qed. + +Theorem div_eucl_spec a b : + let (q,r) := div_eucl a b in a = b * q + r. +Proof. + destruct a as [|a], b as [|b]; unfold div_eucl; trivial. + generalize (pos_div_eucl_spec a (Npos b)). + destruct pos_div_eucl. now rewrite mul_comm. +Qed. + +Theorem div_mod' a b : a = b * (a/b) + (a mod b). +Proof. + generalize (div_eucl_spec a b). + unfold div, modulo. now destruct div_eucl. +Qed. + +Definition div_mod a b : b<>0 -> a = b * (a/b) + (a mod b). +Proof. + intros _. apply div_mod'. +Qed. + +Lemma succ_double_lt n m : n<m -> succ_double n < double m. +Proof. + destruct n as [|n], m as [|m]; intros H; try easy. + unfold lt in *; simpl in *. now rewrite Pos.compare_xI_xO, H. +Qed. + +Theorem pos_div_eucl_remainder (a:positive) (b:N) : + b<>0 -> snd (pos_div_eucl a b) < b. +Proof. + intros Hb. + induction a; cbv beta iota delta [pos_div_eucl]; fold pos_div_eucl; cbv zeta. + (* a~1 *) + destruct pos_div_eucl as (q,r); simpl in *. + case leb_spec; intros H; simpl; trivial. + apply add_lt_cancel_l with b. rewrite add_comm, sub_add by trivial. + destruct b as [|b]; [now destruct Hb| simpl; rewrite Pos.add_diag ]. + apply (succ_double_lt _ _ IHa). + (* a~0 *) + destruct pos_div_eucl as (q,r); simpl in *. + case leb_spec; intros H; simpl; trivial. + apply add_lt_cancel_l with b. rewrite add_comm, sub_add by trivial. + destruct b as [|b]; [now destruct Hb| simpl; rewrite Pos.add_diag ]. + now destruct r. + (* 1 *) + destruct b as [|[ | | ]]; easy || (now destruct Hb). +Qed. + +Theorem mod_lt a b : b<>0 -> a mod b < b. +Proof. + destruct b as [ |b]. now destruct 1. + destruct a as [ |a]. reflexivity. + unfold modulo. simpl. apply pos_div_eucl_remainder. +Qed. + +Theorem mod_bound_pos a b : 0<=a -> 0<b -> 0 <= a mod b < b. +Proof. + intros _ H. split. apply le_0_l. apply mod_lt. now destruct b. +Qed. + +(** Specification of square root *) + +Lemma sqrtrem_sqrt n : fst (sqrtrem n) = sqrt n. +Proof. + destruct n. reflexivity. + unfold sqrtrem, sqrt, Pos.sqrt. + destruct (Pos.sqrtrem p) as (s,r). now destruct r. +Qed. + +Lemma sqrtrem_spec n : + let (s,r) := sqrtrem n in n = s*s + r /\ r <= 2*s. +Proof. + destruct n. now split. + generalize (Pos.sqrtrem_spec p). simpl. + destruct 1; simpl; subst; now split. +Qed. + +Lemma sqrt_spec n : 0<=n -> + let s := sqrt n in s*s <= n < (succ s)*(succ s). +Proof. + intros _. destruct n. now split. apply (Pos.sqrt_spec p). +Qed. + +Lemma sqrt_neg n : n<0 -> sqrt n = 0. +Proof. + now destruct n. +Qed. + +(** Specification of gcd *) + +(** The first component of ggcd is gcd *) + +Lemma ggcd_gcd a b : fst (ggcd a b) = gcd a b. +Proof. + destruct a as [|p], b as [|q]; simpl; auto. + assert (H := Pos.ggcd_gcd p q). + destruct Pos.ggcd as (g,(aa,bb)); simpl; now f_equal. +Qed. + +(** The other components of ggcd are indeed the correct factors. *) + +Lemma ggcd_correct_divisors a b : + let '(g,(aa,bb)) := ggcd a b in + a=g*aa /\ b=g*bb. +Proof. + destruct a as [|p], b as [|q]; simpl; auto. + now rewrite Pos.mul_1_r. + now rewrite Pos.mul_1_r. + generalize (Pos.ggcd_correct_divisors p q). + destruct Pos.ggcd as (g,(aa,bb)); simpl. + destruct 1; split; now f_equal. +Qed. + +(** We can use this fact to prove a part of the gcd correctness *) + +Lemma gcd_divide_l a b : (gcd a b | a). +Proof. + rewrite <- ggcd_gcd. generalize (ggcd_correct_divisors a b). + destruct ggcd as (g,(aa,bb)); simpl. intros (H,_). exists aa; auto. +Qed. + +Lemma gcd_divide_r a b : (gcd a b | b). +Proof. + rewrite <- ggcd_gcd. generalize (ggcd_correct_divisors a b). + destruct ggcd as (g,(aa,bb)); simpl. intros (_,H). exists bb; auto. +Qed. + +(** We now prove directly that gcd is the greatest amongst common divisors *) + +Lemma gcd_greatest a b c : (c|a) -> (c|b) -> (c|gcd a b). +Proof. + destruct a as [ |p], b as [ |q]; simpl; trivial. + destruct c as [ |r]. intros (s,H). discriminate. + intros ([ |s],Hs) ([ |t],Ht); try discriminate; simpl in *. + destruct (Pos.gcd_greatest p q r) as (u,H). + exists s. now inversion Hs. + exists t. now inversion Ht. + exists (Npos u). simpl; now f_equal. +Qed. + +Lemma gcd_nonneg a b : 0 <= gcd a b. +Proof. apply le_0_l. Qed. + +(** Specification of bitwise functions *) + +(** Correctness proofs for [testbit]. *) + +Lemma testbit_even_0 a : testbit (2*a) 0 = false. +Proof. + now destruct a. Qed. +Lemma testbit_odd_0 a : testbit (2*a+1) 0 = true. +Proof. + now destruct a. +Qed. + +Lemma testbit_succ_r_div2 a n : 0<=n -> + testbit a (succ n) = testbit (div2 a) n. +Proof. + intros _. destruct a as [|[a|a| ]], n as [|n]; simpl; trivial; + f_equal; apply Pos.pred_N_succ. +Qed. + +Lemma testbit_odd_succ a n : 0<=n -> + testbit (2*a+1) (succ n) = testbit a n. +Proof. + intros H. rewrite testbit_succ_r_div2 by trivial. f_equal. now destruct a. +Qed. + +Lemma testbit_even_succ a n : 0<=n -> + testbit (2*a) (succ n) = testbit a n. +Proof. + intros H. rewrite testbit_succ_r_div2 by trivial. f_equal. now destruct a. +Qed. + +Lemma testbit_neg_r a n : n<0 -> testbit a n = false. +Proof. + now destruct n. +Qed. + +(** Correctness proofs for shifts *) + +Lemma shiftr_succ_r a n : + shiftr a (succ n) = div2 (shiftr a n). +Proof. + destruct n; simpl; trivial. apply Pos.iter_succ. +Qed. + +Lemma shiftl_succ_r a n : + shiftl a (succ n) = double (shiftl a n). +Proof. + destruct n, a; simpl; trivial. f_equal. apply Pos.iter_succ. +Qed. + +Lemma shiftr_spec a n m : 0<=m -> + testbit (shiftr a n) m = testbit a (m+n). +Proof. + intros _. revert a m. + induction n using peano_ind; intros a m. now rewrite add_0_r. + rewrite add_comm, add_succ_l, add_comm, <- add_succ_l. + now rewrite <- IHn, testbit_succ_r_div2, shiftr_succ_r by apply le_0_l. +Qed. + +Lemma shiftl_spec_high a n m : 0<=m -> n<=m -> + testbit (shiftl a n) m = testbit a (m-n). +Proof. + intros _ H. + rewrite <- (sub_add n m H) at 1. + set (m' := m-n). clearbody m'. clear H m. revert a m'. + induction n using peano_ind; intros a m. + rewrite add_0_r; now destruct a. + rewrite shiftl_succ_r. + rewrite add_comm, add_succ_l, add_comm. + now rewrite testbit_succ_r_div2, div2_double by apply le_0_l. +Qed. + +Lemma shiftl_spec_low a n m : m<n -> + testbit (shiftl a n) m = false. +Proof. + revert a m. + induction n using peano_ind; intros a m H. + elim (le_0_l m). now rewrite <- compare_antisym, H. + rewrite shiftl_succ_r. + destruct m. now destruct (shiftl a n). + rewrite <- (succ_pos_pred p), testbit_succ_r_div2, div2_double by apply le_0_l. + apply IHn. + apply add_lt_cancel_l with 1. rewrite 2 (add_succ_l 0). simpl. + now rewrite succ_pos_pred. +Qed. + +Definition div2_spec a : div2 a = shiftr a 1. +Proof. + reflexivity. +Qed. + +(** Semantics of bitwise operations *) + +Lemma pos_lxor_spec p p' n : + testbit (Pos.lxor p p') n = xorb (Pos.testbit p n) (Pos.testbit p' n). +Proof. + revert p' n. + induction p as [p IH|p IH|]; intros [p'|p'|] [|n]; trivial; simpl; + (specialize (IH p'); destruct Pos.lxor; trivial; now rewrite <-IH) || + (now destruct Pos.testbit). +Qed. + +Lemma lxor_spec a a' n : + testbit (lxor a a') n = xorb (testbit a n) (testbit a' n). +Proof. + destruct a, a'; simpl; trivial. + now destruct Pos.testbit. + now destruct Pos.testbit. + apply pos_lxor_spec. +Qed. + +Lemma pos_lor_spec p p' n : + Pos.testbit (Pos.lor p p') n = (Pos.testbit p n) || (Pos.testbit p' n). +Proof. + revert p' n. + induction p as [p IH|p IH|]; intros [p'|p'|] [|n]; trivial; simpl; + apply IH || now rewrite orb_false_r. +Qed. + +Lemma lor_spec a a' n : + testbit (lor a a') n = (testbit a n) || (testbit a' n). +Proof. + destruct a, a'; simpl; trivial. + now rewrite orb_false_r. + apply pos_lor_spec. +Qed. + +Lemma pos_land_spec p p' n : + testbit (Pos.land p p') n = (Pos.testbit p n) && (Pos.testbit p' n). +Proof. + revert p' n. + induction p as [p IH|p IH|]; intros [p'|p'|] [|n]; trivial; simpl; + (specialize (IH p'); destruct Pos.land; trivial; now rewrite <-IH) || + (now rewrite andb_false_r). +Qed. + +Lemma land_spec a a' n : + testbit (land a a') n = (testbit a n) && (testbit a' n). +Proof. + destruct a, a'; simpl; trivial. + now rewrite andb_false_r. + apply pos_land_spec. +Qed. + +Lemma pos_ldiff_spec p p' n : + testbit (Pos.ldiff p p') n = (Pos.testbit p n) && negb (Pos.testbit p' n). +Proof. + revert p' n. + induction p as [p IH|p IH|]; intros [p'|p'|] [|n]; trivial; simpl; + (specialize (IH p'); destruct Pos.ldiff; trivial; now rewrite <-IH) || + (now rewrite andb_true_r). +Qed. + +Lemma ldiff_spec a a' n : + testbit (ldiff a a') n = (testbit a n) && negb (testbit a' n). +Proof. + destruct a, a'; simpl; trivial. + now rewrite andb_true_r. + apply pos_ldiff_spec. +Qed. + +(** Some constants *) + +Definition zero := 0. +Definition one := 1. +Definition two := 2. + +Lemma one_succ : 1 = succ 0. +Proof. reflexivity. Qed. + +Lemma two_succ : 2 = succ 1. +Proof. reflexivity. Qed. + +Definition pred_0 : pred 0 = 0. +Proof. reflexivity. Qed. + +(** Proof of morphisms, obvious since eq is Leibniz *) + +Local Obligation Tactic := simpl_relation. +Program Definition succ_wd : Proper (eq==>eq) succ := _. +Program Definition pred_wd : Proper (eq==>eq) pred := _. +Program Definition add_wd : Proper (eq==>eq==>eq) add := _. +Program Definition sub_wd : Proper (eq==>eq==>eq) sub := _. +Program Definition mul_wd : Proper (eq==>eq==>eq) mul := _. +Program Definition lt_wd : Proper (eq==>eq==>iff) lt := _. +Program Definition div_wd : Proper (eq==>eq==>eq) div := _. +Program Definition mod_wd : Proper (eq==>eq==>eq) modulo := _. +Program Definition pow_wd : Proper (eq==>eq==>eq) pow := _. +Program Definition testbit_wd : Proper (eq==>eq==>Logic.eq) testbit := _. + +(** Generic induction / recursion *) + +Theorem bi_induction : + forall A : N -> Prop, Proper (Logic.eq==>iff) A -> + A N0 -> (forall n, A n <-> A (succ n)) -> forall n : N, A n. +Proof. +intros A A_wd A0 AS. apply peano_rect. assumption. intros; now apply -> AS. +Qed. + +Definition recursion {A} : A -> (N -> A -> A) -> N -> A := + peano_rect (fun _ => A). + +Instance recursion_wd {A} (Aeq : relation A) : + Proper (Aeq==>(Logic.eq==>Aeq==>Aeq)==>Logic.eq==>Aeq) recursion. +Proof. +intros a a' Ea f f' Ef x x' Ex. subst x'. +induction x using peano_ind. +trivial. +unfold recursion in *. rewrite 2 peano_rect_succ. now apply Ef. +Qed. + +Theorem recursion_0 {A} (a:A) (f:N->A->A) : recursion a f 0 = a. +Proof. reflexivity. Qed. + +Theorem recursion_succ {A} (Aeq : relation A) (a : A) (f : N -> A -> A): + Aeq a a -> Proper (Logic.eq==>Aeq==>Aeq) f -> + forall n : N, Aeq (recursion a f (succ n)) (f n (recursion a f n)). +Proof. +unfold recursion; intros a_wd f_wd n. induction n using peano_ind. +rewrite peano_rect_succ. now apply f_wd. +rewrite !peano_rect_succ in *. now apply f_wd. +Qed. + +(** Instantiation of generic properties of natural numbers *) + +Include !NProp + <+ !UsualMinMaxLogicalProperties <+ !UsualMinMaxDecProperties. + +(* TODO : avoir un inlining selectif : t eq zero one two *) + +End N. + +(** Exportation of notations *) + +Infix "+" := N.add : N_scope. +Infix "-" := N.sub : N_scope. +Infix "*" := N.mul : N_scope. +Infix "^" := N.pow : N_scope. + +Infix "?=" := N.compare (at level 70, no associativity) : N_scope. + +Infix "<=" := N.le : N_scope. +Infix "<" := N.lt : N_scope. +Infix ">=" := N.ge : N_scope. +Infix ">" := N.gt : N_scope. + +Notation "x <= y <= z" := (x <= y /\ y <= z) : N_scope. +Notation "x <= y < z" := (x <= y /\ y < z) : N_scope. +Notation "x < y < z" := (x < y /\ y < z) : N_scope. +Notation "x < y <= z" := (x < y /\ y <= z) : N_scope. + +Infix "=?" := N.eqb (at level 70, no associativity) : N_scope. +Infix "<=?" := N.leb (at level 70, no associativity) : N_scope. +Infix "<?" := N.ltb (at level 70, no associativity) : N_scope. + +Infix "/" := N.div : N_scope. +Infix "mod" := N.modulo (at level 40, no associativity) : N_scope. + +Notation "( p | q )" := (N.divide p q) (at level 0) : N_scope. + (** Compatibility notations *) -Notation N := N (only parsing). +(*Notation N := N (only parsing).*) (*hidden by module N above *) Notation N_rect := N_rect (only parsing). Notation N_rec := N_rec (only parsing). Notation N_ind := N_ind (only parsing). Notation N0 := N0 (only parsing). Notation Npos := Npos (only parsing). + +Notation Ndiscr := N.discr (only parsing). +Notation Ndouble_plus_one := N.succ_double. +Notation Ndouble := N.double (only parsing). +Notation Nsucc := N.succ (only parsing). +Notation Npred := N.pred (only parsing). +Notation Nsucc_pos := N.succ_pos (only parsing). +Notation Ppred_N := Pos.pred_N (only parsing). +Notation Nplus := N.add (only parsing). +Notation Nminus := N.sub (only parsing). +Notation Nmult := N.mul (only parsing). +Notation Neqb := N.eqb (only parsing). +Notation Ncompare := N.compare (only parsing). +Notation Nlt := N.lt (only parsing). +Notation Ngt := N.gt (only parsing). +Notation Nle := N.le (only parsing). +Notation Nge := N.ge (only parsing). +Notation Nmin := N.min (only parsing). +Notation Nmax := N.max (only parsing). +Notation Ndiv2 := N.div2 (only parsing). +Notation Neven := N.even (only parsing). +Notation Nodd := N.odd (only parsing). +Notation Npow := N.pow (only parsing). +Notation Nlog2 := N.log2 (only parsing). + +Notation nat_of_N := N.to_nat (only parsing). +Notation N_of_nat := N.of_nat (only parsing). +Notation N_eq_dec := N.eq_dec (only parsing). +Notation N_ind_double := N.binary_ind (only parsing). +Notation N_rec_double := N.binary_rec (only parsing). +Notation Nrect := N.peano_rect (only parsing). +Notation Nrect_base := N.peano_rect_base (only parsing). +Notation Nrect_step := N.peano_rect_succ (only parsing). +Notation Nind := N.peano_ind (only parsing). +Notation Nrec := N.peano_rec (only parsing). +Notation Nrec_base := N.peano_rec_base (only parsing). +Notation Nrec_succ := N.peano_rec_succ (only parsing). + +Notation Npred_succ := N.pred_succ (only parsing). +Notation Npred_minus := N.pred_sub (only parsing). +Notation Nsucc_pred := N.succ_pred (only parsing). +Notation Ppred_N_spec := N.pos_pred_spec (only parsing). +Notation Nsucc_pos_spec := N.succ_pos_spec (only parsing). +Notation Ppred_Nsucc := N.pos_pred_succ (only parsing). +Notation Nplus_0_l := N.add_0_l (only parsing). +Notation Nplus_0_r := N.add_0_r (only parsing). +Notation Nplus_comm := N.add_comm (only parsing). +Notation Nplus_assoc := N.add_assoc (only parsing). +Notation Nplus_succ := N.add_succ_l (only parsing). +Notation Nsucc_0 := N.succ_0_discr (only parsing). +Notation Nsucc_inj := N.succ_inj (only parsing). +Notation Nminus_N0_Nle := N.sub_0_le (only parsing). +Notation Nminus_0_r := N.sub_0_r (only parsing). +Notation Nminus_succ_r:= N.sub_succ_r (only parsing). +Notation Nmult_0_l := N.mul_0_l (only parsing). +Notation Nmult_1_l := N.mul_1_l (only parsing). +Notation Nmult_1_r := N.mul_1_r (only parsing). +Notation Nmult_comm := N.mul_comm (only parsing). +Notation Nmult_assoc := N.mul_assoc (only parsing). +Notation Nmult_plus_distr_r := N.mul_add_distr_r (only parsing). +Notation Neqb_eq := N.eqb_eq (only parsing). +Notation Nle_0 := N.le_0_l (only parsing). +Notation Ncompare_refl := N.compare_refl (only parsing). +Notation Ncompare_Eq_eq := N.compare_eq (only parsing). +Notation Ncompare_eq_correct := N.compare_eq_iff (only parsing). +Notation Ncompare_antisym := N.compare_antisym (only parsing). +Notation Nlt_irrefl := N.lt_irrefl (only parsing). +Notation Nlt_trans := N.lt_trans (only parsing). +Notation Nle_lteq := N.lt_eq_cases (only parsing). +Notation Nlt_succ_r := N.lt_succ_r (only parsing). +Notation Nle_trans := N.le_trans (only parsing). +Notation Nle_succ_l := N.le_succ_l (only parsing). +Notation Ncompare_spec := N.compare_spec (only parsing). +Notation Ncompare_0 := N.compare_0_r (only parsing). +Notation Ndouble_div2 := N.div2_double (only parsing). +Notation Ndouble_plus_one_div2 := N.div2_succ_double (only parsing). +Notation Ndouble_inj := N.double_inj (only parsing). +Notation Ndouble_plus_one_inj := N.succ_double_inj (only parsing). +Notation Npow_0_r := N.pow_0_r (only parsing). +Notation Npow_succ_r := N.pow_succ_r (only parsing). +Notation Nlog2_spec := N.log2_spec (only parsing). +Notation Nlog2_nonpos := N.log2_nonpos (only parsing). +Notation Neven_spec := N.even_spec (only parsing). +Notation Nodd_spec := N.odd_spec (only parsing). +Notation Nlt_not_eq := N.lt_neq (only parsing). + +(** More complex compatibility facts, expressed as lemmas + (to preserve scopes for instance) *) + +Lemma Nplus_reg_l n m p : n + m = n + p -> m = p. +Proof (proj1 (N.add_cancel_l m p n)). +Lemma Nmult_Sn_m n m : N.succ n * m = m + n * m. +Proof (eq_trans (N.mul_succ_l n m) (N.add_comm _ _)). +Lemma Nmult_plus_distr_l n m p : p * (n + m) = p * n + p * m. +Proof (N.mul_add_distr_l p n m). +Lemma Nmult_reg_r n m p : p <> 0 -> n * p = m * p -> n = m. +Proof (fun H => proj1 (N.mul_cancel_r n m p H)). + +Lemma Ngt_Nlt n m : n > m -> m < n. +Proof. +unfold Ngt, Nlt; intro H. now rewrite <- N.compare_antisym, H. +Qed. + +(** Not kept : Ncompare_n_Sm Nplus_lt_cancel_l *) |