CoRN.model.Zmod.ZDivides


Require Export ZBasics.

The Divides-function over Z

In this section the function Zdivides will be defined. Various facts on this Zdivides will then be proved.

Definition Zdivides (a b : Z) : Prop := q : Z, (q × a)%Z = b.



Section zdivides.

Lemma Zdivides_ref : a : Z, Zdivides a a.
Proof.
 intro.
  1%Z.
 auto with zarith.
Qed.

Lemma Zdivides_trans :
  a b c : Z, Zdivides a bZdivides b cZdivides a c.
Proof.
 intros.
 unfold Zdivides in H; elim H; intros.
 unfold Zdivides in H0; elim H0; intros.
  (x0 × x)%Z.
 rewrite <- H2.
 rewrite <- H1.
 auto with zarith.
Qed.

Lemma Zdivides_zero_rht : z : Z, Zdivides z 0.
Proof.
 intro.
  0%Z.
 auto with zarith.
Qed.

Lemma Zdivides_zero_lft : z : Z, Zdivides 0 zz = 0%Z.
Proof.
 intro z.
 intro Hdiv; elim Hdiv.
 auto with zarith.
Qed.

Lemma Zdivides_one : z : Z, Zdivides 1 z.
Proof.
 intro.
  z.
 auto with zarith.
Qed.


Lemma Zdivides_mult_intro_lft :
  a b c : Z, Zdivides (a × b) cZdivides b c.
Proof.
 intros a b c H.
 unfold Zdivides in H; elim H; intros q H_.
  (q × a)%Z.
 rewrite <- Zmult_assoc.
 assumption.
Qed.

Lemma Zdivides_mult_intro_rht :
  a b c : Z, Zdivides (a × b) cZdivides a c.
Proof.
 intros a b c H.
 unfold Zdivides in H; elim H; intros q H_.
  (q × b)%Z.
 rewrite <- Zmult_assoc.
 rewrite (Zmult_comm b a).
 assumption.
Qed.

Lemma Zdivides_mult_lft : a b : Z, Zdivides b (a × b).
Proof.
 intros.
  a.
 auto with zarith.
Qed.

Lemma Zdivides_mult_rht : a b : Z, Zdivides a (a × b).
Proof.
 intros.
  b.
 auto with zarith.
Qed.

Lemma Zdivides_mult_elim_lft :
  a b c : Z, Zdivides a cZdivides a (b × c).
Proof.
 intros.
 apply (Zdivides_trans a c (b × c)).
  assumption.
 apply Zdivides_mult_lft.
Qed.

Lemma Zdivides_mult_elim_rht :
  a b c : Z, Zdivides a bZdivides a (b × c).
Proof.
 intros.
 apply (Zdivides_trans a b (b × c)).
  assumption.
 apply Zdivides_mult_rht.
Qed.

Lemma Zdivides_mult_cancel_lft :
  a b c : Z, Zdivides a bZdivides (c × a) (c × b).
Proof.
 intros.
 unfold Zdivides in H; elim H; intros.
  x.
 rewrite <- H0.
 rewrite Zmult_assoc.
 rewrite Zmult_assoc.
 rewrite (Zmult_comm x c).
 reflexivity.
Qed.

Lemma Zdivides_mult_cancel_rht :
  a b c : Z, Zdivides a bZdivides (a × c) (b × c).
Proof.
 intros.
 unfold Zdivides in H; elim H; intros.
  x.
 rewrite <- H0.
 auto with zarith.
Qed.

Let Zdiv_one_is_one : a : Z, (a > 0)%ZZdivides a 1 → a = 1%Z.
Proof.
 intros a H0 H1.
 unfold Zdivides in H1; elim H1; intros q H1_.
 apply Zle_antisymm.
  auto with zarith.
 rewrite <- (Zplus_0_l a).
 rewrite <- H1_.
 rewrite <- (Zmult_1_l (0 + a)).
 rewrite (Zplus_0_l a).
 apply (Zmult_pos_mon_le_rht q 1 a); auto with zarith.
 cut (q > 0)%Z; auto with zarith.
 rewrite Zmult_comm in H1_.
 apply (Zdiv_pos_pos a); auto with zarith.
Defined.

Lemma Zdivides_antisymm :
  a b : Z,
 (a > 0)%Z → (b > 0)%ZZdivides a bZdivides b aa = b.
Proof.
 intros a b H01 H02 H1 H2.
 unfold Zdivides in H1; elim H1; intros q1 H1_.
 unfold Zdivides in H2; elim H2; intros q2 H2_.
 generalize H2_; intro H12_.
 rewrite <- H1_ in H12_.
 rewrite Zmult_assoc in H12_.
 rewrite Zmult_comm in H12_.
 rewrite <- H1_.
 rewrite <- (Zmult_1_l a).
 assert (Zdivides q1 1).
  replace 1%Z with (q2 × q1)%Z.
   apply Zdivides_mult_elim_lft.
   apply Zdivides_ref.
  apply (Zunit_eq_one (q2 × q1) a).
   auto with zarith.
  assumption.
 replace q1 with 1%Z.
  auto with zarith.
 symmetry in |- ×.
 rewrite Zmult_comm in H1_; rewrite <- H1_ in H02.
 apply Zdiv_one_is_one; auto.
 apply (Zdiv_pos_pos a); auto.
Qed.

Lemma Zdivides_plus_elim :
  a b c : Z, Zdivides a bZdivides a cZdivides a (b + c).
Proof.
 intros a b c H1 H2.
 unfold Zdivides in H1; elim H1; intros q1 H1_.
 unfold Zdivides in H2; elim H2; intros q2 H2_.
  (q1 + q2)%Z.
 rewrite Zmult_plus_distr_l.
 auto with zarith.
Qed.

Lemma Zdivides_opp_elim_lft :
  a b : Z, Zdivides a bZdivides (- a) b.
Proof.
 intros a b H.
 unfold Zdivides in H; elim H; intros q H_.
  (- q)%Z.
 rewrite Zmult_opp_opp.
 assumption.
Qed.

Lemma Zdivides_opp_elim_rht :
  a b : Z, Zdivides a bZdivides a (- b).
Proof.
 intros a b H.
 unfold Zdivides in H; elim H; intros q H_.
  (- q)%Z.
 rewrite Zopp_mult_distr_l_reverse.
 auto with zarith.
Qed.

Lemma Zdivides_opp_elim :
  a b : Z, Zdivides a bZdivides (- a) (- b).
Proof.
 intros.
 apply Zdivides_opp_elim_lft.
 apply Zdivides_opp_elim_rht.
 assumption.
Qed.

Lemma Zdivides_opp_intro_lft :
  a b : Z, Zdivides (- a) bZdivides a b.
Proof.
 intros a b H.
 rewrite <- (Zopp_involutive a).
 apply (Zdivides_opp_elim_lft _ _ H).
Qed.

Lemma Zdivides_opp_intro_rht :
  a b : Z, Zdivides a (- b) → Zdivides a b.
Proof.
 intros a b H.
 rewrite <- (Zopp_involutive b).
 apply (Zdivides_opp_elim_rht _ _ H).
Qed.

Lemma Zdivides_opp_intro :
  a b : Z, Zdivides (- a) (- b) → Zdivides a b.
Proof.
 intros.
 apply Zdivides_opp_intro_lft.
 apply Zdivides_opp_intro_rht.
 assumption.
Qed.

Lemma Zdivides_minus_elim :
  a b c : Z, Zdivides a bZdivides a cZdivides a (b - c).
Proof.
 intros.
 unfold Zminus in |- ×.
 apply Zdivides_plus_elim.
  assumption.
 apply Zdivides_opp_elim_rht.
 assumption.
Qed.

Lemma Zdivides_mult_elim :
  a b c d : Z, Zdivides a bZdivides c dZdivides (a × c) (b × d).
Proof.
 intros a b c d H1 H2.
 unfold Zdivides in H1; elim H1; intros q1 H1_.
 unfold Zdivides in H2; elim H2; intros q2 H2_.
  (q1 × q2)%Z.
 rewrite <- H1_.
 rewrite <- H2_.
 rewrite Zmult_assoc.
 rewrite Zmult_assoc.
 rewrite <- (Zmult_assoc q1 q2 a).
 rewrite (Zmult_comm q2 a).
 rewrite Zmult_assoc.
 reflexivity.
Qed.

Lemma Zdivides_mult_ll :
  a b c d : Z,
 (a × b)%Z = (c × d)%Za 0%ZZdivides a cZdivides d b.
Proof.
 intros a b c d Heq Ha Hdiv.
 elim Hdiv; intros x Hx.
 rewrite <- Hx in Heq.
  x.
 apply (Zmult_intro_lft a).
  assumption.
 rewrite Heq.
 rewrite Zmult_assoc.
 rewrite (Zmult_comm x a).
 auto.
Qed.

Lemma Zdivides_mult_lr :
  a b c d : Z,
 (a × b)%Z = (d × c)%Za 0%ZZdivides a cZdivides d b.
Proof.
 intros a b c d; rewrite (Zmult_comm d c); apply Zdivides_mult_ll.
Qed.

Lemma Zdivides_mult_rl :
  a b c d : Z,
 (b × a)%Z = (c × d)%Za 0%ZZdivides a cZdivides d b.
Proof.
 intros a b c d; rewrite (Zmult_comm b a); apply Zdivides_mult_ll.
Qed.

Lemma Zdivides_mult_rr :
  a b c d : Z,
 (b × a)%Z = (d × c)%Za 0%ZZdivides a cZdivides d b.
 intros a b c d; rewrite (Zmult_comm b a); rewrite (Zmult_comm d c); apply Zdivides_mult_ll.
Qed.

Lemma Zdivides_abs_elim_lft :
  a b : Z, Zdivides a bZdivides (Zabs a) b.
Proof.
 intros a b.
 case a; simpl in |- *; auto.
 intros p H.
 generalize (Zdivides_opp_elim_lft (Zneg p) b H).
 simpl in |- *; auto.
Qed.

Lemma Zdivides_abs_elim_rht :
  a b : Z, Zdivides a bZdivides a (Zabs b).
Proof.
 intros a b.
 case b; simpl in |- *; auto.
 intros p H.
 generalize (Zdivides_opp_elim_rht a (Zneg p) H).
 simpl in |- *; auto.
Qed.

Lemma Zdivides_abs_elim :
  a b : Z, Zdivides a bZdivides (Zabs a) (Zabs b).
Proof.
 intros.
 apply Zdivides_abs_elim_lft.
 apply Zdivides_abs_elim_rht.
 assumption.
Qed.

Lemma Zdivides_abs_intro_lft :
  a b : Z, Zdivides (Zabs a) bZdivides a b.
Proof.
 intros a b.
 case a; simpl in |- *; auto.
 intros p; apply (Zdivides_opp_intro_lft (Zneg p) b).
Qed.

Lemma Zdivides_abs_intro_rht :
  a b : Z, Zdivides a (Zabs b) → Zdivides a b.
Proof.
 intros a b.
 case b; simpl in |- *; auto.
 intros p; apply (Zdivides_opp_intro_rht a (Zneg p)).
Qed.

Lemma Zdivides_abs_intro :
  a b : Z, Zdivides (Zabs a) (Zabs b) → Zdivides a b.
Proof.
 intros.
 apply Zdivides_abs_intro_lft.
 apply Zdivides_abs_intro_rht.
 assumption.
Qed.

Lemma Zdivisor_pos_le :
  a b : Z, (a > 0)%ZZdivides b a → (a b)%Z.
Proof.
 unfold Zdivides in |- ×.
 intros.
 elim H0.
 intros.
 rewrite <- H1.
 rewrite Zmult_comm.
 apply Zmult_pos_mon.
 rewrite Zmult_comm.
 rewrite H1.
 assumption.
Qed.

Lemma Zdivisor_small :
  a b : Z, Zdivides b a → (Zabs a < b)%Za = 0%Z.
Proof.
 intros a b Hdiv Hlt.
 generalize (Zdivides_abs_elim_rht _ _ Hdiv); intro Hdivabs.
 set (A := a). assert (HA : A = a). auto. generalize HA.
 case A.
   auto.
  intros p Hp.
  assert (Hfalse : (b < b)%Z).
   apply (Zle_lt_trans b (Zabs a) b).
    apply Zge_le.
    apply (Zdivisor_pos_le (Zabs a) b).
     rewrite <- Hp; simpl in |- *; auto with zarith.
    assumption.
   assumption.
  elim (Zlt_irrefl b Hfalse).
 intros p Hp.
 assert (Hfalse : (b < b)%Z).
  apply (Zle_lt_trans b (Zabs a) b).
   apply Zge_le.
   apply (Zdivisor_pos_le (Zabs a) b).
    rewrite <- Hp; simpl in |- ×.
    auto with zarith.
   assumption.
  assumption.
 elim (Zlt_irrefl b Hfalse).
Qed.

Lemma Zmodeq_small :
  a b c : Z,
 (0 a < c)%Z → (0 b < c)%ZZdivides c (a - b) → a = b.
Proof.
 intros a b c Ha Hb Hc.
 cut ((a - b)%Z = 0%Z); auto with zarith.
 apply (Zdivisor_small (a - b) c).
  assumption.
 apply Zabs_lt_elim; auto with zarith.
Qed.

Lemma Zdiv_remainder_unique :
  a b q1 r1 q2 r2 : Z,
 a = (q1 × b + r1)%Z
 (0 r1 < b)%Za = (q2 × b + r2)%Z → (0 r2 < b)%Zr1 = r2.
Proof.
 intros a b q1 r1 q2 r2 Hq1 Hr1 Hq2 Hr2.
 apply (Zmodeq_small r1 r2 b).
   assumption.
  assumption.
 assert ((r1 - r2)%Z = ((q2 - q1) × b)%Z).
  rewrite Hq1 in Hq2.
  rewrite BinInt.Zmult_minus_distr_r.
  auto with zarith.
 rewrite H.
 apply Zdivides_mult_elim_lft.
 apply Zdivides_ref.
Qed.

Lemma Zdiv_quotient_unique :
  a b q1 r1 q2 r2 : Z,
 a = (q1 × b + r1)%Z
 (0 r1 < b)%Za = (q2 × b + r2)%Z → (0 r2 < b)%Zq1 = q2.
Proof.
 intros a b q1 r1 q2 r2 Hq1 Hr1 Hq2 Hr2.
 assert (Hr : r1 = r2).
  apply (Zdiv_remainder_unique a b q1 r1 q2 r2); assumption.
 rewrite Hr in Hq1.
 rewrite Hq1 in Hq2.
 assert (Hb0 : b 0%Z).
  assert (Hbpos : (0 < b)%Z).
   apply (Zle_lt_trans 0 r1 b).
    tauto.
   tauto.
  auto with zarith.
 assert (Hb : (q1 × b)%Z = (q2 × b)%Z).
  auto with zarith.
 apply (Zmult_intro_rht _ _ _ Hb0 Hb).
Qed.

Lemma Zmod0_Zopp :
  a b : Z, b 0%Z → (a mod b)%Z = 0%Z → (a mod - b)%Z = 0%Z.
Proof.
 intros a b.
 generalize (Z_mod_lt (Zabs a) (Zabs b)).
 case a.
   case b; unfold Zabs, Zopp, Zmod, Zdiv_eucl in |- *; auto with zarith.
  case b; unfold Zabs, Zopp, Zmod, Zdiv_eucl in |- ×.
    auto with zarith.
   intros p q.
   elim (Zdiv_eucl_POS q (Zpos p)); intros Q R.
   intros Hlt Hp HR; rewrite HR; auto with zarith.
  intros p q.
  elim (Zdiv_eucl_POS q (Zpos p)); intros Q R.
  case R.
    auto with zarith.
   intro r'; intros H0 H1 H2.
   cut (Zpos r' = Zpos p); auto with zarith.
   fold (- Zpos p)%Z in H2.
   auto with zarith.
  intro r'; intros H0 H1 H2.
  elim H0; auto with zarith.
 case b; unfold Zabs, Zopp, Zmod, Zdiv_eucl in |- ×.
   auto with zarith.
  intros p q.
  elim (Zdiv_eucl_POS q (Zpos p)); intros Q R.
  case R; intros r' H0; intros; try (cut (Zpos r' = Zpos p); elim H0); auto with zarith.
 intros p q.
 elim (Zdiv_eucl_POS q (Zpos p)); intros Q R.
 case R; intros; try discriminate; try tauto.
Qed.

Lemma Zdiv_Zopp :
  a b : Z, (a mod b)%Z = 0%Z → (a / - b)%Z = (- (a / b))%Z.
Proof.
 intros a b.
 unfold Zmod, Zdiv, Zdiv_eucl in |- ×.
 case a.
   auto.
  intro A.
  case b; unfold Zopp in |- ×.
    auto.
   intro B.
   elim (Zdiv_eucl_POS A (Zpos B)); intros q r.
   intro Hr; rewrite Hr; auto.
  intro B.
  generalize (Z_mod_lt (Zpos A) (Zpos B)).
  unfold Zmod, Zdiv_eucl in |- ×.
  elim (Zdiv_eucl_POS A (Zpos B)); intros q r.
  case r.
    intros _ HR; fold (- q)%Z in |- *; fold (- - q)%Z in |- *; rewrite Zopp_involutive; auto.
   intros R Hlt HR.
   assert (H : Zpos R = Zpos B).
    rewrite <- (Zplus_0_r (Zpos B)); rewrite <- HR; rewrite Zplus_assoc; fold (- Zpos B)%Z in |- ×.
    auto with zarith.
   rewrite H in Hlt.
   elim Hlt; auto with zarith.
  intros R Hlt HR.
  elim Hlt; auto with zarith; intro Hfalse; elim Hfalse; auto with zarith.
 intro A.
 case b; unfold Zopp in |- ×.
   auto.
  intro B.
  generalize (Z_mod_lt (Zpos A) (Zpos B)).
  unfold Zmod, Zdiv_eucl in |- ×.
  elim (Zdiv_eucl_POS A (Zpos B)); intros q r.
  case r.
    intros _ HR; fold (- q)%Z in |- *; fold (- - q)%Z in |- *; rewrite Zopp_involutive; auto.
   intros R Hlt HR.
   assert (H : Zpos R = Zpos B).
    rewrite <- (Zplus_0_r (Zpos R)); rewrite <- HR; unfold Zminus in |- *;
      rewrite Zplus_assoc; auto with zarith.
   rewrite H in Hlt.
   elim Hlt; auto with zarith.
  intros R Hlt HR.
  elim Hlt; auto with zarith; intro Hfalse; elim Hfalse; auto with zarith.
 intro B.
 generalize (Z_mod_lt (Zpos A) (Zpos B)).
 unfold Zmod, Zdiv_eucl in |- ×.
 elim (Zdiv_eucl_POS A (Zpos B)); intros q r.
 case r.
   intros _ HR; fold (- q)%Z in |- *; auto.
  intros; discriminate.
 intros; discriminate.
Qed.

Lemma Zmod0_Zdivides_pos :
  a b : Z, (b > 0)%ZZdivides b a → (a mod b)%Z = 0%Z.
Proof.
 intros a b Hb Hdiv.
 elim Hdiv; intros q Hq.
 rewrite (Z_div_mod_eq a b) in Hq.
  rewrite <- (Zplus_0_r (q × b)) in Hq.
  symmetry in |- ×.
  apply (Zdiv_remainder_unique (q × b + 0) b q 0 (a / b) (a mod b)).
     reflexivity.
    auto with zarith.
   rewrite (Zmult_comm (a / b) b); exact Hq.
  apply Z_mod_lt; auto with zarith.
 exact Hb.
Qed.

Lemma Zdivides_Zmod0_pos :
  a b : Z, (b > 0)%Z → (a mod b)%Z = 0%ZZdivides b a.
Proof.
 intros a b Hb Hmod.
 rewrite (Z_div_mod_eq a b).
  rewrite (Zmult_comm b (a / b)); rewrite Hmod; rewrite Zplus_0_r.
   (a / b)%Z.
  reflexivity.
 exact Hb.
Qed.

Lemma Zmod0_Zdivides :
  a b : Z, b 0%ZZdivides b a → (a mod b)%Z = 0%Z.
Proof.
 intros a b.
 case b.
   tauto.
  intros p _; apply Zmod0_Zdivides_pos; auto with zarith.
 intros p _.
 generalize (Zmod0_Zdivides_pos a (Zpos p)); intro H.
 fold (- Zpos p)%Z in |- ×.
 intro Hdiv.
 apply Zmod0_Zopp.
  intro; discriminate.
 apply H.
  auto with zarith.
 rewrite <- (Zopp_involutive (Zpos p)).
 apply Zdivides_opp_elim_lft.
 assumption.
Qed.

Lemma Zdivides_Zmod0 :
  a b : Z, b 0%Z → (a mod b)%Z = 0%ZZdivides b a.
Proof.
 intros a b.
 case b.
   tauto.
  intros p _; apply Zdivides_Zmod0_pos; auto with zarith.
 intros p _.
 generalize (Zdivides_Zmod0_pos a (Zpos p)); intro H.
 fold (- Zpos p)%Z in |- ×.
 intro Hmod.
 apply Zdivides_opp_elim_lft.
 apply H.
  auto with zarith.
 rewrite <- (Zopp_involutive (Zpos p)).
 apply Zmod0_Zopp.
  simpl in |- *; intros; discriminate.
 assumption.
Qed.

Lemma Zmod_mult_cancel_lft : a b : Z, ((a × b) mod a)%Z = 0%Z.
Proof.
 intros a b.
 case a.
   auto with zarith.
  intro p.
  apply Zmod0_Zdivides_pos.
   auto with zarith.
  apply Zdivides_mult_elim_rht.
  apply Zdivides_ref.
 intro p.
 apply Zmod0_Zdivides.
  auto with zarith.
 apply Zdivides_mult_elim_rht.
 apply Zdivides_ref.
Qed.

Lemma Zmod_mult_cancel_rht : a b : Z, ((a × b) mod b)%Z = 0%Z.
Proof.
 intros a b.
 rewrite Zmult_comm.
 apply Zmod_mult_cancel_lft.
Qed.

Lemma Zdiv_mult_cancel_lft : a b : Z, a 0%Z → (a × b / a)%Z = b.
Proof.
 intros a b.
 case a.
   auto with zarith.
  intros p _.
  apply (Zdiv_quotient_unique (Zpos p × b) (Zpos p) (Zpos p × b / Zpos p)
    ((Zpos p × b) mod Zpos p) b 0).
     rewrite (Zmult_comm (Zpos p × b / Zpos p) (Zpos p)).
     apply Z_div_mod_eq; auto with zarith.
    apply Z_mod_lt; auto with zarith.
   rewrite Zplus_0_r; auto with zarith.
  auto with zarith.
 intros p _.
 fold (- Zpos p)%Z in |- ×.
 rewrite Zdiv_Zopp.
  cut ((- Zpos p × b / Zpos p)%Z = (- b)%Z); auto with zarith.
  unfold Zopp in |- *; fold (- b)%Z in |- ×.
  apply (Zdiv_quotient_unique (Zneg p × b) (Zpos p) (Zneg p × b / Zpos p)
    ((Zneg p × b) mod Zpos p) (- b) 0).
     rewrite (Zmult_comm (Zneg p × b / Zpos p) (Zpos p)).
     apply Z_div_mod_eq; auto with zarith.
    apply Z_mod_lt; auto with zarith.
   rewrite Zplus_0_r; rewrite Zmult_opp_comm; fold (- Zpos p)%Z in |- *; auto with zarith.
  auto with zarith.
 rewrite Zmult_opp_comm.
 apply Zmod_mult_cancel_lft.
Qed.

Lemma Zdiv_mult_cancel_rht : a b : Z, b 0%Z → (a × b / b)%Z = a.
Proof.
 intros a b.
 rewrite Zmult_comm.
 apply Zdiv_mult_cancel_lft.
Qed.

Lemma Zdiv_plus_elim :
  a b d : Z,
 Zdivides d aZdivides d b → ((a + b) / d)%Z = (a / d + b / d)%Z.
Proof.
 intros a b d Ha Hb.
 case (Zdec d).
  intro Hd; rewrite Hd; case (a + b)%Z; case a; case b; simpl in |- *; auto.
 intro Hd.
 elim Ha; clear Ha; intros x Ha; rewrite <- Ha.
 elim Hb; clear Hb; intros y Hb; rewrite <- Hb.
 rewrite <- Zmult_plus_distr_l.
 repeat rewrite Zdiv_mult_cancel_rht; auto.
Qed.

Lemma Zdiv_elim :
  a b d : Z,
 d 0%ZZdivides d aZdivides d b → (a / d)%Z = (b / d)%Za = b.
Proof.
 intros a b d Hd Ha Hb.
 elim Ha; clear Ha; intros x Ha; rewrite <- Ha.
 elim Hb; clear Hb; intros y Hb; rewrite <- Hb.
 repeat rewrite Zdiv_mult_cancel_rht; auto.
 intro Hxy; rewrite Hxy; auto.
Qed.

Lemma Zabs_div_lft : a : Z, (Zabs a / a)%Z = Zsgn a.
Proof.
 intro a.
 rewrite Zmult_sgn_eq_abs.
 case (Zdec a).
  intro Ha. rewrite Ha. simpl in |- ×. auto with zarith.
  apply Zdiv_mult_cancel_rht.
Qed.

Lemma Zabs_div_rht : a : Z, (a / Zabs a)%Z = Zsgn a.
Proof.
 intro a.
 set (A := Zabs a).
 set (sa := Zsgn a).
 replace a with (Zabs a × Zsgn a)%Z.
  unfold sa in |- *; clear sa.
  case (Zdec A).
   unfold A in |- *; intro HA.
   cut (a = 0%Z); auto with zarith.
   intro Ha; rewrite Ha; auto with zarith.
  unfold A in |- *; apply Zdiv_mult_cancel_lft.
 rewrite Zmult_comm.
 auto with zarith.
Qed.

Lemma Zdiv_same : a : Z, a 0%Z → (a / a)%Z = 1%Z.
Proof.
 intros a.
 case a.
   tauto.
  intros; apply Z_div_same; auto with zarith.
 intros A HA.
 fold (- Zpos A)%Z in |- ×.
 rewrite Zdiv_Zopp.
  simpl in |- ×.
  replace (Zpos A) with (Zabs (Zneg A)); auto.
  rewrite Zabs_div_rht.
  auto.
 replace (- Zpos A)%Z with (-1 × Zpos A)%Z; auto with zarith.
 apply Zmod_mult_cancel_rht.
Qed.

Lemma Zmult_div_simpl_1 :
  a b c d : Z,
 (a × b)%Z = (c × d)%Za 0%ZZdivides a cZdivides d b.
Proof.
 intros a b c d Heq Ha Hdiv.
 elim Hdiv; intros x Hx.
 rewrite <- Hx in Heq.
 rewrite (Zmult_comm x a) in Heq.
 rewrite <- Zmult_assoc in Heq.
  x.
 apply (Zmult_intro_lft a); auto.
Qed.

Lemma Zmult_div_simpl_2 :
  a b c d : Z,
 (a × b)%Z = (d × c)%Za 0%ZZdivides a cZdivides d b.
Proof.
 intros a b c d; rewrite (Zmult_comm d c); apply Zmult_div_simpl_1.
Qed.

Lemma Zmult_div_simpl_3 :
  a b c d : Z,
 (b × a)%Z = (c × d)%Za 0%ZZdivides a cZdivides d b.
Proof.
 intros a b c d; rewrite (Zmult_comm b a); apply Zmult_div_simpl_1.
Qed.

Lemma Zmult_div_simpl_4 :
  a b c d : Z,
 (b × a)%Z = (d × c)%Za 0%ZZdivides a cZdivides d b.
 intros a b c d; rewrite (Zmult_comm b a); rewrite (Zmult_comm d c); apply Zmult_div_simpl_1.
Qed.

Lemma Zdivides_dec : a b : Z, {Zdivides a b} + {¬ Zdivides a b}.
Proof.
 intros a b.
 case (Zdec b).
  intro Hb.
  rewrite Hb.
  left.
  apply Zdivides_zero_rht.
 intro Hb.
 case (Zdec a).
  intro Ha.
  rewrite Ha.
  right.
  intro H0.
  rewrite (Zdivides_zero_lft b H0) in Hb.
  elim Hb.
  auto.
 intro Ha.
 generalize (Zdivides_Zmod0 b a Ha).
 generalize (Zmod0_Zdivides b a Ha).
 case (Zdec (b mod a)); auto.
Qed.

End zdivides.

Hint Resolve Zdivides_zero_lft: zarith.
Hint Resolve Zdivides_zero_rht: zarith.
Hint Resolve Zdivides_one: zarith.
Hint Resolve Zdivides_ref: zarith.
Hint Resolve Zdivides_trans: zarith.
Hint Resolve Zdivides_mult_intro_lft: zarith.
Hint Resolve Zdivides_mult_intro_rht: zarith.
Hint Resolve Zdivides_mult_lft: zarith.
Hint Resolve Zdivides_mult_rht: zarith.
Hint Resolve Zdivides_mult_elim_lft: zarith.
Hint Resolve Zdivides_mult_elim_rht: zarith.
Hint Resolve Zdivides_mult_cancel_lft: zarith.
Hint Resolve Zdivides_mult_cancel_rht: zarith.
Hint Resolve Zdivides_antisymm: zarith.
Hint Resolve Zdivides_plus_elim: zarith.
Hint Resolve Zdivides_opp_elim_lft: zarith.
Hint Resolve Zdivides_opp_elim_rht: zarith.
Hint Resolve Zdivides_opp_elim: zarith.
Hint Resolve Zdivides_opp_intro_lft: zarith.
Hint Resolve Zdivides_opp_intro_rht: zarith.
Hint Resolve Zdivides_opp_intro: zarith.
Hint Resolve Zdivides_minus_elim: zarith.
Hint Resolve Zdivides_mult_elim: zarith.
Hint Resolve Zdivides_mult_ll: zarith.
Hint Resolve Zdivides_mult_lr: zarith.
Hint Resolve Zdivides_mult_rl: zarith.
Hint Resolve Zdivides_mult_rr: zarith.
Hint Resolve Zdivides_abs_elim_lft: zarith.
Hint Resolve Zdivides_abs_elim_rht: zarith.
Hint Resolve Zdivides_abs_elim: zarith.
Hint Resolve Zdivides_abs_intro_lft: zarith.
Hint Resolve Zdivides_abs_intro_rht: zarith.
Hint Resolve Zdivides_abs_intro: zarith.
Hint Resolve Zdivisor_pos_le: zarith.
Hint Resolve Zdivisor_small: zarith.
Hint Resolve Zmodeq_small: zarith.
Hint Resolve Zdiv_remainder_unique: zarith.
Hint Resolve Zdiv_quotient_unique: zarith.
Hint Resolve Zmod0_Zopp: zarith.
Hint Resolve Zdiv_Zopp: zarith.
Hint Resolve Zmod0_Zdivides: zarith.
Hint Resolve Zdivides_Zmod0: zarith.
Hint Resolve Zmod_mult_cancel_lft: zarith.
Hint Resolve Zmod_mult_cancel_rht: zarith.
Hint Resolve Zdiv_mult_cancel_lft: zarith.
Hint Resolve Zdiv_mult_cancel_rht: zarith.
Hint Resolve Zdiv_plus_elim: zarith.
Hint Resolve Zdiv_elim: zarith.
Hint Resolve Zabs_div_lft: zarith.
Hint Resolve Zabs_div_rht: zarith.
Hint Resolve Zdiv_same: zarith.
Hint Resolve Zmult_div_simpl_1: zarith.
Hint Resolve Zmult_div_simpl_2: zarith.
Hint Resolve Zmult_div_simpl_3: zarith.
Hint Resolve Zmult_div_simpl_4: zarith.
Hint Resolve Zdivides_dec: zarith.

Section ineq.

Lemma Zmod_POS_nonNEG :
  a b p : positive, (Zpos a mod Zpos b)%Z Zneg p.
Proof.
 intros a b p.
 generalize (Z_mod_lt (Zpos a) (Zpos b)).
 intro H.
 elim H.
  intros H0 H1.
  intro Hfalse.
  rewrite Hfalse in H0.
  elim H0.
  auto with zarith.
 auto with zarith.
Qed.

Lemma Zdiv_POS :
  a b : positive, (Zpos b × (Zpos a / Zpos b) Zpos a)%Z.
Proof.
 intros a b.
 rewrite <- (Zplus_0_r (Zpos b × (Zpos a / Zpos b))).
 set (lhs := (Zpos b × (Zpos a / Zpos b) + 0)%Z) in ×.
 rewrite (Z_div_mod_eq (Zpos a) (Zpos b)).
  unfold lhs in |- ×.
  apply Zplus_le_compat_l.
  auto with zarith.
  generalize (Z_mod_lt (Zpos a) (Zpos b)).
  intro H.
  elim H.
   auto with zarith.
  auto with zarith.
 auto with zarith.
Qed.

Lemma Zmod_lt_POS :
  a b : positive, (Zpos a < Zpos b)%Z → (Zpos a mod Zpos b)%Z = Zpos a.
Proof.
 intros a b Hlt.
 apply (Zdiv_remainder_unique (Zpos a) (Zpos b) (Zpos a / Zpos b)
   (Zpos a mod Zpos b) 0 (Zpos a)); auto with zarith.
  rewrite Zmult_comm.
  apply Z_div_mod_eq; auto with zarith.
 apply Z_mod_lt; auto with zarith.
Qed.

Lemma Zdiv_lt_POS :
  a b : positive, (Zpos a < Zpos b)%Z → (Zpos a / Zpos b)%Z = 0%Z.
Proof.
 intros a b Hlt.
 apply (Zdiv_quotient_unique (Zpos a) (Zpos b) (Zpos a / Zpos b)
   (Zpos a mod Zpos b) 0 (Zpos a)); auto with zarith.
  rewrite Zmult_comm.
  apply Z_div_mod_eq; auto with zarith.
 apply Z_mod_lt; auto with zarith.
Qed.

End ineq.

Hint Resolve Zmod_POS_nonNEG: zarith.
Hint Resolve Zdiv_POS: zarith.
Hint Resolve Zmod_lt_POS: zarith.
Hint Resolve Zdiv_lt_POS: zarith.