Module Coq.ZArith.Zcomplements

Require ZArith.
Require Omega.
Require Wf_nat.

Multiplication by a number >0 preserves Zcompare. It also perserves Zle, Zlt, Zge, Zgt

Implicit Arguments On.

Lemma Zmult_zero : (x,y:Z)`x*y=0` -> `x=0` \/ `y=0`.
NewDestruct x; NewDestruct y; Auto.
Simpl; Intros; Discriminate H.
Simpl; Intros; Discriminate H.
Simpl; Intros; Discriminate H.
Simpl; Intros; Discriminate H.
Save.

Lemma Zeq_Zminus : (x,y:Z)x=y -> `x-y = 0`.
Intros; Omega.
Save.

Lemma Zminus_Zeq : (x,y:Z)`x-y=0` -> x=y.
Intros; Omega.
Save.

Lemma Zmult_Zminus_distr_l : (x,y,z:Z)`(x-y)*z = x*z - y*z`.
Intros; Unfold Zminus.
Rewrite <- Zopp_Zmult.
Apply Zmult_plus_distr_l.
Save.

Lemma Zmult_Zminus_distr_r : (x,y,z:Z)`z*(x-y) = z*x - z*y`.
Intros; Rewrite (Zmult_sym z `x-y`).
Rewrite (Zmult_sym z x).
Rewrite (Zmult_sym z y).
Apply Zmult_Zminus_distr_l.
Save.

Lemma Zmult_reg_left : (x,y,z:Z)`z>0` -> `z*x=z*y` -> x=y.
Intros.
Generalize (Zeq_Zminus H0).
Intro.
Apply Zminus_Zeq.
Rewrite <- (Zmult_Zminus_distr_r x y z) in H1.
Elim (Zmult_zero H1).
Omega.
Trivial.
Save.

Lemma Zmult_reg_right : (x,y,z:Z)`z>0` -> `x*z=y*z` -> x=y.
Intros x y z Hz.
Rewrite (Zmult_sym x z).
Rewrite (Zmult_sym y z).
Intro; Apply Zmult_reg_left with z; Assumption.
Save.
    
Lemma Zgt0_le_pred : (y:Z) `y > 0` -> `0 <= (Zpred y)`.
Intro; Unfold Zpred; Omega.
Save.

Lemma Zlt_Zplus :
  (x1,x2,y1,y2:Z)`x1 < x2` -> `y1 < y2` -> `x1 + y1 < x2 + y2`.
Intros; Omega.
Save.

Lemma Zlt_Zmult_right : (x,y,z:Z)`z>0` -> `x < y` -> `x*z < y*z`.

Intros; Rewrite (Zs_pred z); Generalize (Zgt0_le_pred H); Intro;
Apply natlike_ind with P:=[z:Z]`x*(Zs z) < y*(Zs z)`;
[ Simpl; Do 2 (Rewrite Zmult_n_1); Assumption
| Unfold Zs; Intros x0 Hx0; Do 6 (Rewrite Zmult_plus_distr_r);
  Repeat Rewrite Zmult_n_1;
  Intro; Apply Zlt_Zplus; Assumption
| Assumption ].
Save.

Lemma Zlt_Zmult_right2 : (x,y,z:Z)`z>0` -> `x*z < y*z` -> `x < y`.
Intros x y z H; Rewrite (Zs_pred z).
Apply natlike_ind with P:=[z:Z]`x*(Zs z) < y*(Zs z)`->`x < y`.
Simpl; Do 2 Rewrite Zmult_n_1; Auto 1.
Unfold Zs.
Intros x0 Hx0; Repeat Rewrite Zmult_plus_distr_r.
Repeat Rewrite Zmult_n_1.
Omega.
Unfold Zpred; Omega.
Save.

Lemma Zle_Zmult_right : (x,y,z:Z)`z>0` -> `x <= y` -> `x*z <= y*z`.
Intros x y z Hz Hxy.
Elim (Zle_lt_or_eq x y Hxy).
Intros; Apply Zlt_le_weak.
Apply Zlt_Zmult_right; Trivial.
Intros; Apply Zle_refl.
Rewrite H; Trivial.
Save.

Lemma Zle_Zmult_right2 : (x,y,z:Z)`z>0` -> `x*z <= y*z` -> `x <= y`.
Intros x y z Hz Hxy.
Elim (Zle_lt_or_eq `x*z` `y*z` Hxy).
Intros; Apply Zlt_le_weak.
Apply Zlt_Zmult_right2 with z; Trivial.
Intros; Apply Zle_refl.
Apply Zmult_reg_right with z; Trivial.
Save.

Lemma Zgt_Zmult_right : (x,y,z:Z)`z>0` -> `x > y` -> `x*z > y*z`.

Intros; Apply Zlt_gt; Apply Zlt_Zmult_right;
[ Assumption | Apply Zgt_lt ; Assumption ].
Save.

Lemma Zlt_Zmult_left : (x,y,z:Z)`z>0` -> `x < y` -> `z*x < z*y`.

Intros;
Rewrite (Zmult_sym z x); Rewrite (Zmult_sym z y);
Apply Zlt_Zmult_right; Assumption.
Save.

Lemma Zgt_Zmult_left : (x,y,z:Z)`z>0` -> `x > y` -> `z*x > z*y`.
Intros;
Rewrite (Zmult_sym z x); Rewrite (Zmult_sym z y);
Apply Zgt_Zmult_right; Assumption.
Save.

Theorem Zcompare_Zmult_right : (x,y,z:Z)` z>0` -> `x ?= y`=`x*z ?= y*z`.

Intros; Apply Zcompare_egal_dec;
[ Intros; Apply Zlt_Zmult_right; Trivial
| Intro Hxy; Apply [a,b:Z](let (t1,t2)=(Zcompare_EGAL a b) in t2);
  Rewrite ((let (t1,t2)=(Zcompare_EGAL x y) in t1) Hxy); Trivial
| Intros; Apply Zgt_Zmult_right; Trivial
].
Save.

Theorem Zcompare_Zmult_left : (x,y,z:Z)`z>0` -> `x ?= y`=`z*x ?= z*y`.
Intros;
Rewrite (Zmult_sym z x);
Rewrite (Zmult_sym z y);
Apply Zcompare_Zmult_right; Assumption.
Save.

Section diveucl.

Lemma two_or_two_plus_one : (x:Z) { y:Z | `x = 2*y`}+{ y:Z | `x = 2*y+1`}.
NewDestruct x.
Left ; Split with ZERO; Reflexivity.

NewDestruct p.
Right ; Split with (POS p); Reflexivity.

Left ; Split with (POS p); Reflexivity.

Right ; Split with ZERO; Reflexivity.

NewDestruct p.
Right ; Split with (NEG (add xH p)).
Rewrite NEG_xI.
Rewrite NEG_add.
Omega.

Left ; Split with (NEG p); Reflexivity.

Right ; Split with `-1`; Reflexivity.
Save.

The biggest power of 2 that is stricly less than a

Easy to compute: replace all "1" of the binary representation by "0", except the first "1" (or the first one :-)

Fixpoint floor_pos [a : positive] : positive :=
  Cases a of
  | xH => xH
  | (xO a') => (xO (floor_pos a'))
  | (xI b') => (xO (floor_pos b'))
  end.

Definition floor := [a:positive](POS (floor_pos a)).

Lemma floor_gt0 : (x:positive) `(floor x) > 0`.
Intro.
Compute.
Trivial.
Save.

Lemma floor_ok : (a:positive)
  `(floor a) <= (POS a) < 2*(floor a)`.
Unfold floor.
Induction a.

Intro p; Simpl.
Repeat Rewrite POS_xI.
Rewrite (POS_xO (xO (floor_pos p))).
Rewrite (POS_xO (floor_pos p)).
Omega.

Intro p; Simpl.
Repeat Rewrite POS_xI.
Rewrite (POS_xO (xO (floor_pos p))).
Rewrite (POS_xO (floor_pos p)).
Rewrite (POS_xO p).
Omega.

Simpl; Omega.
Save.

Lemma Zdiv_eucl_POS : (b:Z)`b > 0` -> (p:positive)
  { qr:Z*Z | let (q,r)=qr in `(POS p)=b*q+r` /\ `0 <= r < b` }.

Induction p.

Intros p' ((q,r), (Hrec1, Hrec2)).
Elim (Z_lt_ge_dec `2*r+1` b);
[ Exists `(2*q, 2*r+1)`;
  Rewrite POS_xI;
  Rewrite Hrec1;
  Split;
  [ Rewrite Zmult_Zplus_distr;
    Rewrite Zplus_assoc_l;
    Rewrite (Zmult_permute b `2`);
    Reflexivity
  | Omega ]
| Exists `(2*q+1, 2*r+1-b)`;
  Rewrite POS_xI;
  Rewrite Hrec1;
  Split;
  [ Do 2 Rewrite Zmult_Zplus_distr;
    Unfold Zminus;
    Do 2 Rewrite Zplus_assoc_l;
    Rewrite <- (Zmult_permute `2` b);
    Generalize `b*q`; Intros; Omega
  | Omega ]
].

Intros p' ((q,r), (Hrec1, Hrec2)).
Elim (Z_lt_ge_dec `2*r` b);
[ Exists `(2*q,2*r)`;
  Rewrite POS_xO;
  Rewrite Hrec1;
  Split;
  [ Rewrite Zmult_Zplus_distr;
    Rewrite (Zmult_permute b `2`);
    Reflexivity
  | Omega ]
| Exists `(2*q+1, 2*r-b)`;
  Rewrite POS_xO;
  Rewrite Hrec1;
  Split;
  [ Do 2 Rewrite Zmult_Zplus_distr;
    Unfold Zminus;
    Rewrite <- (Zmult_permute `2` b);
    Generalize `b*q`; Intros; Omega
  | Omega ]
].
Elim (Z_le_gt_dec `2` b);
[ Exists `(0,1)`; Omega
| Exists `(1,0)`; Omega
].
Save.

Theorem Zdiv_eucl : (b:Z)`b > 0` -> (a:Z)
  { qr:Z*Z | let (q,r)=qr in `a=b*q+r` /\ `0 <= r < b` }.
NewDestruct a;

[ Exists `(0,0)`; Omega
| Intros; Apply Zdiv_eucl_POS; Auto
| Intros; Elim (Zdiv_eucl_POS H p);
  Intros (q,r) (Hp1, Hp2);
  Elim (Z_le_gt_dec r `0`);
  [ Exists `(-q,0)`; Split;
    [ Apply Zopp_intro; Simpl; Rewrite Hp1;
      Rewrite Zero_right;
      Rewrite <- Zopp_Zmult;
      Rewrite Zmult_Zopp_Zopp;
      Generalize `b*q`; Intro; Omega
    | Omega
    ]
  | Exists `(-(q+1),b-r)`; Split;
    [ Apply Zopp_intro;
      Unfold Zminus; Simpl; Rewrite Hp1;
      Repeat Rewrite Zopp_Zplus;
      Repeat Rewrite <- Zopp_Zmult;
      Rewrite Zmult_Zplus_distr;
      Rewrite Zmult_Zopp_Zopp;
      Rewrite Zplus_assoc_r;
      Apply f_equal with f:=[c:Z]`b*q+c`;
      Omega
    | Omega ]
  ]
].
Save.

Definition Zdiv [a,b:Z] : Z :=
  Cases (Z_gt_le_dec b `0`) of
    (left bpos) => let (qr,_) = (Zdiv_eucl bpos a) in
                   let (q,_) = qr in q
  | (right _) => `0` end.

Definition Zmod [a,b:Z] : Z :=
  Cases (Z_gt_le_dec b `0`) of
    (left bpos) => let (qr,_) = (Zdiv_eucl bpos a) in
                   let (_,r) = qr in r
  | (right _) => `0` end.

Lemma Z_div_mod : (a,b:Z)`b > 0` -> `a = (Zdiv a b)*b + (Zmod a b)`.
Proof.
Intros; Unfold Zdiv Zmod; Case (Z_gt_le_dec b `0`); Simpl; Intros.
Case (Zdiv_eucl z a); Simpl; Induction x; Intros.
Rewrite <- Zmult_sym; Tauto.
Absurd `b > 0`; Omega.
Save.

Lemma Z_mod_bounds : (a,b:Z)`b > 0` -> `0 <= (Zmod a b) < b`.
Proof.
Intros; Unfold Zdiv Zmod; Case (Z_gt_le_dec b `0`); Simpl; Intros.
Case (Zdiv_eucl z a); Simpl; Induction x; Intros; Omega.
Absurd `b > 0`; Omega.
Save.

Theorem Zdiv_eucl_extended : (b:Z)`b <> 0` -> (a:Z)
  { qr:Z*Z | let (q,r)=qr in `a=b*q+r` /\ `0 <= r < |b|` }.
Proof.
Intros b Hb a.
Elim (Z_le_gt_dec `0` b);Intro Hb'.
Cut `b>0`;[Intro Hb''|Omega].
Rewrite Zabs_eq;[Apply Zdiv_eucl;Assumption|Assumption].
Cut `-b>0`;[Intro Hb''|Omega].
Elim (Zdiv_eucl Hb'' a);Intros qr.
Elim qr;Intros q r Hqr.
Exists (pair ? ? `-q` r).
Elim Hqr;Intros.
Split.
Rewrite <- Zmult_Zopp_left;Assumption.
Rewrite Zabs_non_eq;[Assumption|Omega].
Save.

End diveucl.

Two more induction principles over Z.

Theorem Z_lt_abs_rec : (P: Z -> Set)
  ((n: Z) ((m: Z) `|m|<|n|` -> (P m)) -> (P n)) -> (p: Z) (P p).
Intros P HP p.
LetTac Q:=[z]`0<=z`->(P z)*(P `-z`).
Cut (Q `|p|`);[Intros|Apply (Z_lt_rec Q);Auto with zarith].
Elim (Zabs_dec p);Intro eq;Rewrite eq;Elim H;Auto with zarith.
Unfold Q;Clear Q;Intros.
Apply pair;Apply HP.
Rewrite Zabs_eq;Auto;Intros.
Elim (H `|m|`);Intros;Auto with zarith.
Elim (Zabs_dec m);Intro eq;Rewrite eq;Trivial.
Rewrite Zabs_non_eq;Auto with zarith.
Rewrite Zopp_Zopp;Intros.
Elim (H `|m|`);Intros;Auto with zarith.
Elim (Zabs_dec m);Intro eq;Rewrite eq;Trivial.
Qed.

Theorem Z_lt_abs_induction : (P: Z -> Prop)
  ((n: Z) ((m: Z) `|m|<|n|` -> (P m)) -> (P n)) -> (p: Z) (P p).
Intros P HP p.
LetTac Q:=[z]`0<=z`->(P z) /\ (P `-z`).
Cut (Q `|p|`);[Intros|Apply (Z_lt_induction Q);Auto with zarith].
Elim (Zabs_dec p);Intro eq;Rewrite eq;Elim H;Auto with zarith.
Unfold Q;Clear Q;Intros.
Split;Apply HP.
Rewrite Zabs_eq;Auto;Intros.
Elim (H `|m|`);Intros;Auto with zarith.
Elim (Zabs_dec m);Intro eq;Rewrite eq;Trivial.
Rewrite Zabs_non_eq;Auto with zarith.
Rewrite Zopp_Zopp;Intros.
Elim (H `|m|`);Intros;Auto with zarith.
Elim (Zabs_dec m);Intro eq;Rewrite eq;Trivial.
Qed.


Index