Library div

(c) Copyright Microsoft Corporation and Inria. All rights reserved. 
This file deals with divisibility for natural numbers.                 
It contains the definitions of:                                        
     edivn m d   == the pair composed of the quotient and remainder    
                    of the euclidian division of m by d                
         m %/ d  == quotient of m by d                                 
         m %% d  == remainder of m dy d                                
 m = n %[mod d]  <=> m equals n modulo d                               
 m == n %[mod d] <=> m equals n modulo d (boolean version)             
 m <> n %[mod d] <=> m differs from n modulo d                         
 m != n %[mod d] <=> m differs from n modulo d (boolean version)       
          d %| m <=> d divides m                                       
        gcdn m n == the GCD of m and n                                 
       egcdn m n == the extended GCD of m and n                        
        lcmn m n == the LCM of m and n                                 
     coprime m n <=> m and n are coprime                               
 chinese m n r s == witness of the chinese remainder theorem           

Import Prenex Implicits.


Definition edivn_rec d := fix loop (m q : nat) {struct m} :=
  if m - d is m'.+1 then loop m' q.+1 else (q, m).

Definition edivn m d := if d > 0 then edivn_rec d.-1 m 0 else (0, m).

CoInductive edivn_spec (m d : nat) : nat * nat -> Type :=
  EdivnSpec q r of m = q * d + r & (d > 0) ==> (r < d) : edivn_spec m d (q, r).

Lemma edivnP : forall m d, edivn_spec m d (edivn m d).

Lemma edivn_eq : forall d q r, r < d -> edivn (q * d + r) d = (q, r).

Definition divn m d := (edivn m d).1.

Notation "m %/ d" := (divn m d) (at level 40, no associativity) : nat_scope.

We redefine modn so that it is structurally decreasing. 

Definition modn_rec d := fix loop (m : nat) :=
  if m - d is m'.+1 then loop m' else m.

Definition modn m d := if d > 0 then modn_rec d.-1 m else m.

Notation "m %% d" := (modn m d) (at level 40, no associativity) : nat_scope.
Notation "m = n %[mod d ]" := (m %% d = n %% d)
  (at level 70, n at next level,
   format "'[hv ' m '/' = n '/' %[mod d ] ']'") : nat_scope.
Notation "m == n %[mod d ]" := (m %% d == n %% d)
  (at level 70, n at next level,
   format "'[hv ' m '/' == n '/' %[mod d ] ']'") : nat_scope.
Notation "m <> n %[mod d ]" := (m %% d <> n %% d)
  (at level 70, n at next level,
   format "'[hv ' m '/' <> n '/' %[mod d ] ']'") : nat_scope.
Notation "m != n %[mod d ]" := (m %% d != n %% d)
  (at level 70, n at next level,
   format "'[hv ' m '/' != n '/' %[mod d ] ']'") : nat_scope.

Lemma modn_def : forall m d, m %% d = (edivn m d).2.

Lemma edivn_def : forall m d, edivn m d = (m %/ d, m %% d).

Lemma divn_eq : forall m d, m = m %/ d * d + m %% d.

Lemma div0n : forall d, 0 %/ d = 0. Qed.

Lemma divn0 : forall m, m %/ 0 = 0. Qed.

Lemma mod0n : forall d, 0 %% d = 0. Qed.

Lemma modn0 : forall m, m %% 0 = m. Qed.

Lemma divn_small : forall m d, m < d -> m %/ d = 0.

Lemma divn_addl_mul : forall q m d, 0 < d -> (q * d + m) %/ d = q + m %/ d.

Lemma mulnK : forall m d, 0 < d -> m * d %/ d = m.

Lemma mulKn : forall m d, 0 < d -> d * m %/ d = m.

Lemma modn1 : forall m, m %% 1 = 0.

Lemma divn1: forall m, m %/ 1 = m.

Lemma divnn : forall d, d %/ d = (0 < d).

Lemma divn_pmul2l : forall p m d, p > 0 -> p * m %/ (p * d) = m %/ d.
Implicit Arguments divn_pmul2l [p m d].

Lemma divn_pmul2r : forall p m d, p > 0 -> m * p %/ (d * p) = m %/ d.
Implicit Arguments divn_pmul2r [p m d].

Lemma ltn_mod : forall m d, (m %% d < d) = (0 < d).

Lemma ltn_pmod : forall m d, 0 < d -> m %% d < d.

Lemma leq_floor : forall m d, m %/ d * d <= m.

Lemma leq_mod : forall m d, m %% d <= m.

Lemma leq_div : forall m d, m %/ d <= m.

Lemma ltn_ceil : forall m d, 0 < d -> m < (m %/ d).+1 * d.

Lemma ltn_divl : forall m n d, d > 0 -> (m %/ d < n) = (m < n * d).

Lemma leq_divr : forall m n d, d > 0 -> (m <= n %/ d) = (m * d <= n).

Lemma ltn_Pdiv : forall m d, 1 < d -> 0 < m -> m %/ d < m.

Lemma divn_gt0 : forall d m, 0 < d -> (0 < m %/ d) = (d <= m).

Lemma divn_divl : forall m n p, m %/ n %/ p = m %/ (n * p).

Lemma divnAC : forall m n p, m %/ n %/ p = m %/ p %/ n.

Lemma modn_small : forall m d, m < d -> m %% d = m.

Lemma modn_mod : forall m d, m %% d = m %[mod d].

Lemma modn_addl_mul : forall p m d, p * d + m = m %[mod d].

Lemma modn_pmul2l : forall p m d, 0 < p -> p * m %% (p * d) = p * (m %% d).
Implicit Arguments modn_pmul2l [p m d].

Lemma modn_addl : forall m d, d + m = m %[mod d].

Lemma modn_addr : forall m d, m + d = m %[mod d].

Lemma modnn : forall d, d %% d = 0.

Lemma modn_mull : forall p d, p * d %% d = 0.

Lemma modn_mulr : forall p d, d * p %% d = 0.

Lemma modn_addml : forall m n d, m %% d + n = m + n %[mod d].

Lemma modn_addmr : forall m n d, m + n %% d = m + n %[mod d].

Lemma modn_add2m : forall m n d, m %% d + n %% d = m + n %[mod d].

Lemma modn_mulml : forall m n d, m %% d * n = m * n %[mod d].

Lemma modn_mulmr : forall m n d, m * (n %% d) = m * n %[mod d].

Lemma modn_mul2m : forall m n d, m %% d * (n %% d) = m * n %[mod d].

Lemma modn2 : forall m, m %% 2 = odd m.

Lemma divn2 : forall m, m %/ 2 = m./2.

Lemma odd_mod : forall m d, odd d = false -> odd (m %% d) = odd m.

Lemma modn_exp: forall m n a, (a %% n) ^ m = a ^ m %[mod n].


Definition dvdn d m := m %% d == 0.

Notation "m %| d" := (dvdn m d) (at level 70, no associativity) : nat_scope.

Lemma dvdn2 : forall n, (2 %| n) = ~~ odd n.

Lemma dvdnP : forall d m, reflect (exists k, m = k * d) (d %| m).
Implicit Arguments dvdnP [d m].

Lemma dvdn0 : forall d, d %| 0.

Lemma dvd0n : forall n, (0 %| n) = (n == 0).

Lemma dvdn1 : forall d, (d %| 1) = (d == 1).

Lemma dvd1n : forall m, 1 %| m.

Lemma dvdn_gt0 : forall d m, m > 0 -> d %| m -> d > 0.

Lemma dvdnn: forall m, m %| m.

Lemma dvdn_mull: forall d m n, d %| n -> d %| m * n.

Lemma dvdn_mulr: forall d m n, d %| m -> d %| m * n.

Hint Resolve dvdn0 dvd1n dvdnn dvdn_mull dvdn_mulr.

Lemma dvdn_mul: forall d1 d2 m1 m2, d1 %| m1 -> d2 %| m2 -> d1 * d2 %| m1 * m2.

Lemma dvdn_trans: forall n d m, d %| n -> n %| m -> d %| m.

Lemma dvdn_eq : forall d m, (d %| m) = (m %/ d * d == m).

Lemma divnK : forall d m, d %| m -> m %/ d * d = m.

Lemma leq_divl : forall d m n, d %| m -> (m %/ d <= n) = (m <= n * d).

Lemma ltn_divr : forall d m n, d %| m -> (n < m %/ d) = (n * d < m).

Lemma eqn_div : forall d m n, d > 0 -> d %| m -> (n == m %/ d) = (n * d == m).

Lemma eqn_mul : forall d m n, d > 0 -> d %| m -> (m == n * d) = (m %/ d == n).

Lemma divn_mulAC : forall d m n, d %| m -> m %/ d * n = m * n %/ d.

Lemma divn_mulA : forall d m n, d %| n -> m * (n %/ d) = m * n %/ d.

Lemma divn_mulCA : forall d m n,
  d %| m -> d %| n -> m * (n %/ d) = n * (m %/ d).

Lemma divn_divr : forall m n p, p %| n -> m %/ (n %/ p) = m * p %/ n.

Lemma modn_dvdm : forall m n d, d %| m -> n %% m = n %[mod d].

Lemma dvdn_leq : forall d m, 0 < m -> d %| m -> d <= m.

Lemma gtnNdvd : forall n d, 0 < n -> n < d -> (d %| n) = false.

Lemma eqn_dvd : forall m n, (m == n) = (m %| n) && (n %| m).

Lemma dvdn_pmul2l : forall p d m, 0 < p -> (p * d %| p * m) = (d %| m).
Implicit Arguments dvdn_pmul2l [p m d].

Lemma dvdn_pmul2r : forall p d m, 0 < p -> (d * p %| m * p) = (d %| m).
Implicit Arguments dvdn_pmul2r [p m d].

Lemma dvdn_addr : forall m d n, d %| m -> (d %| m + n) = (d %| n).

Lemma dvdn_addl : forall n d m, d %| n -> (d %| m + n) = (d %| m).

Lemma dvdn_add : forall d m n, d %| m -> d %| n -> d %| m + n.

Lemma dvdn_add_eq : forall d m n, d %| m + n -> (d %| m) = (d %| n).

Lemma dvdn_subr : forall d m n, n <= m -> d %| m -> (d %| m - n) = (d %| n).

Lemma dvdn_subl : forall d m n, n <= m -> d %| n -> (d %| m - n) = (d %| m).

Lemma dvdn_sub : forall d m n, d %|m -> d %| n -> d %| m - n.

Lemma dvdn_exp : forall k d m, 0 < k -> d %| m -> d %| (m ^ k).

Hint Resolve dvdn_add dvdn_sub dvdn_exp.

Lemma eqn_mod_dvd : forall d m n, n <= m -> (m == n %[mod d]) = (d %| m - n).

Lemma divn_addl : forall m n d, d %| m -> (m + n) %/ d = m %/ d + n %/ d.

Lemma divn_addr : forall m n d, d %| n -> (m + n) %/ d = m %/ d + n %/ d.

  A function that computes the gcd of 2 numbers                     

Fixpoint gcdn_rec (m n : nat) {struct m} :=
  let n' := n %% m in if n' is 0 then m else
  if m - n'.-1 is m'.+1 then gcdn_rec (m' %% n') n' else n'.

Definition gcdn := nosimpl gcdn_rec.

Lemma gcdnE : forall m n, gcdn m n = if m == 0 then n else gcdn (n %% m) m.

Lemma gcdnn : idempotent gcdn.

Lemma gcdnC : commutative gcdn.

Lemma gcd0n : left_id 0 gcdn. Qed.

Lemma gcdn0 : right_id 0 gcdn. Qed.

Lemma gcd1n : left_zero 1 gcdn.

Lemma gcdn1 : right_zero 1 gcdn.

Lemma dvdn_gcdr : forall m n, gcdn m n %| n.

Lemma dvdn_gcdl : forall m n, gcdn m n %| m.

Lemma gcdn_gt0 : forall m n, (0 < gcdn m n) = (0 < m) || (0 < n).

Lemma gcdn_addl_mul : forall k m n, gcdn m (k * m + n) = gcdn m n.

Lemma gcdn_addl: forall m n, gcdn m (m + n) = gcdn m n.

Lemma gcdn_addr: forall m n, gcdn m (n + m) = gcdn m n.

Lemma gcdn_mull : forall n m, gcdn n (m * n) = n.

Lemma gcdn_mulr : forall n m, gcdn n (n * m) = n.

Extended gcd, which computes Bezout coefficients. 

Fixpoint bezout_rec (km kn : nat) (qs : seq nat) {struct qs} :=
  if qs is q :: qs' then bezout_rec kn (NatTrec.add_mul q kn km) qs'
  else (km, kn).

Fixpoint egcdn_rec (m n s : nat) (qs : seq nat) {struct s} :=
  if s is s'.+1 then
    let: (q, r) := edivn m n in
    if r > 0 then egcdn_rec n r s' (q :: qs) else
    if odd (size qs) then qs else q.-1 :: qs
  else [::0].

Definition egcdn m n := bezout_rec 0 1 (egcdn_rec m n n [::]).

CoInductive egcdn_spec (m n : nat) : nat * nat -> Type :=
  EgcdnSpec km kn of km * m = kn * n + gcdn m n & kn * gcdn m n < m :
    egcdn_spec m n (km, kn).

Lemma egcd0n : forall n, egcdn 0 n = (1, 0).

Lemma egcdnP : forall m n, m > 0 -> egcdn_spec m n (egcdn m n).

Lemma bezoutl : forall m n, m > 0 -> {a | a < m & m %| gcdn m n + a * n}.

Lemma bezoutr : forall m n, n > 0 -> {a | a < n & n %| gcdn m n + a * m}.

Back to the gcd. 

Lemma dvdn_gcd : forall p m n, p %| gcdn m n = (p %| m) && (p %| n).

Lemma gcdn_mul2l : forall p m n, gcdn (p * m) (p * n) = p * gcdn m n.

Lemma gcdn_modr : forall m n, gcdn m (n %% m) = gcdn m n.

Lemma gcdn_modl: forall m n, gcdn (m %% n) n = gcdn m n.

Lemma gcdnAC : right_commutative gcdn.

Lemma gcdnA : associative gcdn.

Lemma gcdnCA : left_commutative gcdn.

Lemma muln_gcdl : left_distributive muln gcdn.

Lemma muln_gcdr : right_distributive muln gcdn.

Lemma gcdn_def : forall d m n,
    d %| m -> d %| n -> (forall d', d' %| m -> d' %| n -> d' %| d)
  -> gcdn m n = d.

Lemma gcdn_divnC : forall n m, n * (m %/ gcdn n m) = m * (n %/ gcdn n m).

We derive the lcm directly. 

Definition lcmn m n := m * n %/ gcdn m n.

Lemma lcmnC : commutative lcmn.

Lemma lcm0n : left_zero 0 lcmn. Qed.

Lemma lcmn0 : right_zero 0 lcmn. Qed.

Lemma lcm1n : left_id 1 lcmn.

Lemma lcmn1 : right_id 1 lcmn.

Lemma muln_lcm_gcd : forall m n, lcmn m n * gcdn m n = m * n.

Lemma lcmn_gt0 : forall m n, (0 < lcmn m n) = (0 < m) && (0 < n).

Lemma muln_lcmr : right_distributive muln lcmn.

Lemma muln_lcml : left_distributive muln lcmn.

Lemma lcmnA : associative lcmn.

Lemma dvdn_lcml : forall d1 d2, d1 %| lcmn d1 d2.

Lemma dvdn_lcmr : forall d1 d2, d2 %| lcmn d1 d2.

Lemma dvdn_lcm : forall d1 d2 m, lcmn d1 d2 %| m = (d1 %| m) && (d2 %| m).

Coprime factors 

Definition coprime m n := gcdn m n == 1.

Lemma coprime1n : forall n, coprime 1 n.

Lemma coprimen1 : forall n, coprime n 1.

Lemma coprime_sym : forall m n, coprime m n = coprime n m.

Lemma coprime_modl : forall m n, coprime (m %% n) n = coprime m n.

Lemma coprime_modr : forall m n, coprime m (n %% m) = coprime m n.

Lemma coprimeP : forall n m, n > 0 ->
  reflect (exists u, u.1 * n - u.2 * m = 1) (coprime n m).

Lemma modn_coprime : forall k n, O < k ->
  (exists u, (k * u) %% n = 1%N) -> coprime k n.

Lemma gauss_inv : forall m n p,
  coprime m n -> (m * n %| p) = (m %| p) && (n %| p).

Lemma gauss : forall m n p, coprime m n -> (m %| n * p) = (m %| p).

Lemma gauss_gcdr : forall p m n, coprime p m -> gcdn p (m * n) = gcdn p n.

Lemma gauss_gcdl : forall p m n, coprime p n -> gcdn p (m * n) = gcdn p m.

Lemma coprime_mulr : forall p m n,
  coprime p (m * n) = coprime p m && coprime p n.

Lemma coprime_mull : forall p m n,
  coprime (m * n) p = coprime m p && coprime n p.

Lemma coprime_pexpl : forall k m n, 0 < k -> coprime (m ^ k) n = coprime m n.

Lemma coprime_pexpr : forall k m n, 0 < k -> coprime m (n ^ k) = coprime m n.

Lemma coprime_expl : forall k m n, coprime m n -> coprime (m ^ k) n.

Lemma coprime_expr : forall k m n, coprime m n -> coprime m (n ^ k).

Lemma coprime_egcdn : forall n m, n > 0 ->
    coprime (egcdn n m).1 (egcdn n m).2.

Section Chinese.

  The chinese remainder theorem                                     

Variables m1 m2 : nat.
Hypothesis co_m12 : coprime m1 m2.

Lemma chinese_remainder : forall x y,
  (x == y %[mod m1 * m2]) = (x == y %[mod m1]) && (x == y %[mod m2]).

  A function that solves the chinese remainder problem              

Definition chinese r1 r2 :=
  r1 * m2 * (egcdn m2 m1).1 + r2 * m1 * (egcdn m1 m2).1.

Lemma chinese_modl : forall r1 r2, chinese r1 r2 = r1 %[mod m1].

Lemma chinese_modr : forall r1 r2, chinese r1 r2 = r2 %[mod m2].

Lemma chinese_modlr : forall x, x = chinese (x %% m1) (x %% m2) %[mod m1 * m2].

End Chinese.