(* ========================================================================= *)
(* Mangoldt function and elementary Chebyshev/Mertens results.               *)
(* ========================================================================= *)

needs "Library/pocklington.ml";;
needs "Multivariate/transcendentals.ml";;

prioritize_real();;

(* ------------------------------------------------------------------------- *)
(* Useful approximation/bound lemmas, simple rather than sharp.              *)
(* ------------------------------------------------------------------------- *)

let LOG_FACT = prove
 (`!n. log(&(FACT n)) = sum(1..n) (\d. log(&d))`,
  INDUCT_TAC THEN
  SIMP_TAC[FACT; SUM_CLAUSES_NUMSEG; LOG_1; ARITH; ARITH_RULE `1 <= SUC n`] THEN
  SIMP_TAC[GSYM REAL_OF_NUM_MUL; LOG_MUL; REAL_OF_NUM_LT; FACT_LT; LT_0] THEN
  ASM_REWRITE_TAC[ADD1] THEN REWRITE_TAC[ADD_AC; REAL_ADD_AC]);;

let SUM_DIVISORS_FLOOR_LEMMA = prove
 (`!n d. ~(d = 0)
         ==> sum(1..n) (\m. if d divides m then &1 else &0) = floor(&n / &d)`,
  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[FLOOR_DIV_DIV] THEN
  SIMP_TAC[GSYM SUM_RESTRICT_SET; FINITE_NUMSEG; SUM_CONST; FINITE_RESTRICT;
           REAL_MUL_RID; REAL_OF_NUM_EQ] THEN
  GEN_REWRITE_TAC RAND_CONV [GSYM CARD_NUMSEG_1] THEN
  MATCH_MP_TAC BIJECTIONS_CARD_EQ THEN
  MAP_EVERY EXISTS_TAC [`\m:num. m DIV d`; `\m:num. m * d`] THEN
  ASM_SIMP_TAC[IN_ELIM_THM; IN_NUMSEG; LE_1; DIV_MULT; DIVIDES_DIV_MULT;
               FINITE_NUMSEG; ONCE_REWRITE_RULE[MULT_SYM] DIV_MULT;
               DIV_MONO; LE_1] THEN
  ASM_SIMP_TAC[LE_RDIV_EQ; MULT_EQ_0; ARITH_RULE `1 <= n <=> ~(n = 0)`] THEN
  CONJ_TAC THENL [GEN_TAC THEN STRIP_TAC; ARITH_TAC] THEN
  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN ASM_SIMP_TAC[DIV_EQ_0] THEN
  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [ARITH_RULE `d = 1 * d`] THEN
  ASM_SIMP_TAC[LT_MULT_RCANCEL; ARITH_RULE `n < 1 <=> n = 0`] THEN
  ASM_MESON_TAC[MULT_CLAUSES]);;

let LOG_2_BOUNDS = prove
 (`&1 / &2 <= log(&2) /\ log(&2) <= &1`,
  CONJ_TAC THENL
   [GEN_REWRITE_TAC LAND_CONV [GSYM LOG_EXP] THEN
    MP_TAC(SPEC `inv(&2)` REAL_EXP_BOUND_LEMMA);
    GEN_REWRITE_TAC RAND_CONV [GSYM LOG_EXP] THEN
    MP_TAC(SPEC `&1` REAL_EXP_LE_X)] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN MATCH_MP_TAC EQ_IMP THEN
  CONV_TAC SYM_CONV THEN MATCH_MP_TAC LOG_MONO_LE THEN
  REWRITE_TAC[REAL_EXP_POS_LT; REAL_OF_NUM_LT; ARITH]);;

let LOG_LE_REFL = prove
 (`!n. ~(n = 0) ==> log(&n) <= &n`,
  REPEAT STRIP_TAC THEN
  MATCH_MP_TAC(REAL_ARITH `x <= y - &1 ==> x <= y`) THEN
  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV)
   [REAL_ARITH `n = &1 + (n  - &1)`] THEN
  MATCH_MP_TAC LOG_LE THEN
  REWRITE_TAC[REAL_LE_SUB_LADD; REAL_OF_NUM_ADD; REAL_OF_NUM_LE] THEN
  UNDISCH_TAC `~(n = 0)` THEN ARITH_TAC);;

let LOG_FACT_BOUNDS = prove
 (`!n. ~(n = 0)
       ==> abs(log(&(FACT n)) - (&n * log(&n) - &n + &1)) <= &2 * log(&n)`,
  REPEAT STRIP_TAC THEN ASM_CASES_TAC `n = 1` THENL
   [ASM_REWRITE_TAC[num_CONV `1`; FACT] THEN
    REWRITE_TAC[ARITH; LOG_1] THEN REAL_ARITH_TAC;
    ALL_TAC] THEN
  ASM_SIMP_TAC[LOG_FACT] THEN
  REWRITE_TAC[REAL_ARITH `abs(x - y) <= e <=> x <= y + e /\ y - e <= x`] THEN
  CONJ_TAC THENL
   [MP_TAC(ISPECL[`\z. clog(z)`; `\z. z * clog z - z`; `1`; `n:num`]
                 SUM_INTEGRAL_UBOUND_INCREASING) THEN
    REWRITE_TAC[] THEN ANTS_TAC THENL
     [CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
      CONJ_TAC THENL
       [REWRITE_TAC[IN_SEGMENT_CX_GEN] THEN REPEAT STRIP_TAC THENL
         [COMPLEX_DIFF_TAC THEN CONJ_TAC THEN UNDISCH_TAC `&1 <= Re x` THENL
           [REAL_ARITH_TAC; ALL_TAC] THEN
          ASM_CASES_TAC `x = Cx(&0)` THEN ASM_REWRITE_TAC[RE_CX] THENL
           [REAL_ARITH_TAC;
            UNDISCH_TAC `~(x = Cx(&0))` THEN CONV_TAC COMPLEX_FIELD];
          FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM LT_NZ]) THEN
          REWRITE_TAC[GSYM REAL_OF_NUM_LT] THEN
          ASM_REAL_ARITH_TAC];
        MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN STRIP_TAC THEN
        SUBGOAL_THEN `&0 < a /\ &0 < b` ASSUME_TAC THENL
         [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
        ASM_SIMP_TAC[GSYM CX_LOG; RE_CX; LOG_MONO_LE_IMP]];
        ALL_TAC];
     ASM_SIMP_TAC[SUM_CLAUSES_LEFT; ARITH_RULE `1 <= n <=> ~(n = 0)`] THEN
     REWRITE_TAC[LOG_1; REAL_ADD_LID; ARITH] THEN
     FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
      `~(n = 0) ==> n = 1 \/ 2 <= n`))
     THENL
      [ASM_REWRITE_TAC[] THEN CONV_TAC(ONCE_DEPTH_CONV NUMSEG_CONV) THEN
       REWRITE_TAC[LOG_1; SUM_CLAUSES] THEN REAL_ARITH_TAC;
       ALL_TAC] THEN
     MP_TAC(ISPECL[`\z. clog(z)`; `\z. z * clog z - z`; `2`; `n:num`]
                  SUM_INTEGRAL_LBOUND_INCREASING) THEN
     REWRITE_TAC[] THEN ANTS_TAC THENL
      [CONJ_TAC THENL [POP_ASSUM MP_TAC THEN ARITH_TAC; ALL_TAC] THEN
       CONV_TAC REAL_RAT_REDUCE_CONV THEN CONJ_TAC THENL
        [REWRITE_TAC[IN_SEGMENT_CX_GEN] THEN REPEAT STRIP_TAC THENL
          [COMPLEX_DIFF_TAC THEN CONJ_TAC THEN UNDISCH_TAC `&1 <= Re x` THENL
            [REAL_ARITH_TAC; ALL_TAC] THEN
           ASM_CASES_TAC `x = Cx(&0)` THEN ASM_REWRITE_TAC[RE_CX] THENL
            [REAL_ARITH_TAC;
             UNDISCH_TAC `~(x = Cx(&0))` THEN CONV_TAC COMPLEX_FIELD];
           FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_OF_NUM_LE]) THEN
           ASM_REAL_ARITH_TAC];
        MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN STRIP_TAC THEN
        SUBGOAL_THEN `&0 < a /\ &0 < b` ASSUME_TAC THENL
         [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
        ASM_SIMP_TAC[GSYM CX_LOG; RE_CX; LOG_MONO_LE_IMP]];
       ALL_TAC]] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN
  MATCH_MP_TAC(REAL_ARITH `y <= x /\ a <= b ==> x <= a ==> y <= b`) THEN
  ASM_SIMP_TAC[GSYM CX_LOG; SUM_EQ_NUMSEG; REAL_OF_NUM_LT; LE_1; CLOG_1;
               ARITH_RULE `2 <= n ==> 0 < n`; RE_CX;
               REAL_ARITH `&0 < &n + &1`; REAL_EQ_IMP_LE] THEN
  REWRITE_TAC[GSYM CX_MUL; GSYM CX_SUB; GSYM CX_ADD; RE_CX] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_SUB_RNEG] THENL
   [REWRITE_TAC[REAL_ARITH
     `(n + &1) * l' - (n + &1) + &1 <= (n * l - n + &1) + k * l <=>
      (n + &1) * l' <= (n + k) * l + &1`] THEN
    MATCH_MP_TAC REAL_LE_TRANS THEN
    EXISTS_TAC `(&n + &1) * (log(&n) + &1 / &n)` THEN CONJ_TAC THENL
     [MATCH_MP_TAC REAL_LE_LMUL THEN
      CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
      REWRITE_TAC[REAL_ARITH `x <= y + z <=> x - y <= z`] THEN
      ASM_SIMP_TAC[GSYM LOG_DIV; REAL_OF_NUM_LT; LT_NZ;
                   REAL_ARITH `&0 < &n + &1`;
                   REAL_FIELD `&0 < x ==> (x + &1) / x = &1 + &1 / x`] THEN
      MATCH_MP_TAC LOG_LE THEN SIMP_TAC[REAL_LE_DIV; REAL_POS];
      ALL_TAC] THEN
    REWRITE_TAC[REAL_ARITH
    `(n + &1) * (l + n') <= (n + k) * l + &1 <=>
      n' * (n + &1) <= (k - &1) * l + &1`] THEN
    ASM_SIMP_TAC[REAL_OF_NUM_EQ; REAL_LE_RADD; REAL_FIELD
     `~(n = &0) ==> &1 / n * (n + &1) = inv(n) + &1`] THEN
    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `inv(&2)` THEN CONJ_TAC THENL
     [MATCH_MP_TAC REAL_LE_INV2 THEN
      REWRITE_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
      ASM_ARITH_TAC;
      ALL_TAC] THEN
    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_MUL_LID] THEN
    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `log(&2)` THEN
    REWRITE_TAC[LOG_2_BOUNDS] THEN MATCH_MP_TAC LOG_MONO_LE_IMP THEN
    REWRITE_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LE] THEN ASM_ARITH_TAC;
    SUBGOAL_THEN `&0 <= log(&n)` MP_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
    MATCH_MP_TAC LOG_POS THEN REWRITE_TAC[REAL_OF_NUM_LE] THEN
    ASM_ARITH_TAC]);;

(* ------------------------------------------------------------------------- *)
(* The Mangoldt function and its key expansion.                              *)
(* ------------------------------------------------------------------------- *)

let mangoldt = new_definition
 `mangoldt n = if ?p k. 1 <= k /\ prime p /\ n = p EXP k
               then log(&(@p. prime p /\ p divides n))
               else &0`;;

let MANGOLDT_1 = prove
 (`mangoldt 1 = &0`,
  REWRITE_TAC[mangoldt] THEN
  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
  REWRITE_TAC[EXP_EQ_1] THEN MESON_TAC[PRIME_1; ARITH_RULE `~(1 <= 0)`]);;

let MANGOLDT_PRIMEPOW = prove
 (`!p k. prime p ==> mangoldt(p EXP k) = if 1 <= k then log(&p) else &0`,
  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[mangoldt] THEN
  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`] THEN
  ASM_SIMP_TAC[EQ_PRIME_EXP; LE_1] THEN
  REWRITE_TAC[TAUT `~(a /\ b ==> ~(c /\ d)) <=> d /\ c /\ a /\ b`] THEN
  ASM_REWRITE_TAC[UNWIND_THM1] THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT AP_TERM_TAC THEN
  ASM_SIMP_TAC[DIVIDES_PRIMEPOW] THEN MATCH_MP_TAC SELECT_UNIQUE THEN
  ASM_MESON_TAC[PRIME_DIVEXP; prime; PRIME_1; DIVIDES_REFL; EXP_1]);;

let MANGOLDT_POS_LE = prove
 (`!n. &0 <= mangoldt n`,
  GEN_TAC THEN ASM_CASES_TAC `?p k. 1 <= k /\ prime p /\ n = p EXP k` THENL
   [FIRST_X_ASSUM(REPEAT_TCL CHOOSE_THEN STRIP_ASSUME_TAC) THEN
    ASM_SIMP_TAC[MANGOLDT_PRIMEPOW] THEN MATCH_MP_TAC LOG_POS THEN
    REWRITE_TAC[REAL_OF_NUM_LE] THEN
    FIRST_X_ASSUM(MP_TAC o MATCH_MP PRIME_GE_2) THEN ARITH_TAC;
    ASM_REWRITE_TAC[mangoldt; REAL_LE_REFL]]);;

let LOG_MANGOLDT_SUM = prove
 (`!n. ~(n = 0) ==> log(&n) = sum {d | d divides n} (\d. mangoldt(d))`,
  REPEAT STRIP_TAC THEN ASM_CASES_TAC `n = 1` THENL
   [ASM_REWRITE_TAC[LOG_1; DIVIDES_ONE; SET_RULE `{x | x = a} = {a}`] THEN
    REWRITE_TAC[SUM_SING; mangoldt] THEN
    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
    REWRITE_TAC[EXP_EQ_1] THEN MESON_TAC[PRIME_1; ARITH_RULE `~(1 <= 0)`];
    ALL_TAC] THEN
  SUBGOAL_THEN `1 < n` MP_TAC THENL
   [ASM_ARITH_TAC; ALL_TAC] THEN
  SPEC_TAC(`n:num`,`n:num`) THEN POP_ASSUM_LIST(K ALL_TAC) THEN
  MATCH_MP_TAC INDUCT_COPRIME THEN REPEAT STRIP_TAC THENL
   [ASM_SIMP_TAC[LOG_MUL; GSYM REAL_OF_NUM_MUL; REAL_OF_NUM_LT;
                 ARITH_RULE `1 < a ==> 0 < a`] THEN
    MATCH_MP_TAC EQ_TRANS THEN
    EXISTS_TAC
     `sum ({d | d divides a} UNION {d | d divides b}) (\d. mangoldt d)` THEN
    CONJ_TAC THEN CONV_TAC SYM_CONV THENL
     [MATCH_MP_TAC SUM_UNION_NONZERO THEN REWRITE_TAC[IN_INTER] THEN
      ASM_SIMP_TAC[FINITE_DIVISORS; ARITH_RULE `1 < n ==> ~(n = 0)`] THEN
      REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[coprime; MANGOLDT_1];
      MATCH_MP_TAC SUM_SUPERSET THEN REWRITE_TAC[UNION_SUBSET; IN_UNION] THEN
      SIMP_TAC[SUBSET; IN_ELIM_THM; DIVIDES_LMUL; DIVIDES_RMUL] THEN
      X_GEN_TAC `d:num` THEN STRIP_TAC THEN REWRITE_TAC[mangoldt] THEN
      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
      ASM_MESON_TAC[PRIME_DIVPROD_POW]];
    ALL_TAC] THEN
  ASM_SIMP_TAC[DIVIDES_PRIMEPOW; GSYM REAL_OF_NUM_POW] THEN
  REWRITE_TAC[SET_RULE `{d | ?i. i <= k /\ d = p EXP i} =
                        IMAGE (\i. p EXP i) {i | i <= k}`] THEN
  ASM_SIMP_TAC[EQ_EXP; SUM_IMAGE; PRIME_GE_2;
               ARITH_RULE `2 <= p ==> ~(p = 0) /\ ~(p = 1)`] THEN
  ASM_SIMP_TAC[MANGOLDT_PRIMEPOW; o_DEF] THEN
  ASM_SIMP_TAC[GSYM SUM_RESTRICT_SET; IN_ELIM_THM; FINITE_NUMSEG_LE] THEN
  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[GSYM numseg] THEN
  ASM_SIMP_TAC[LOG_POW; PRIME_IMP_NZ; REAL_OF_NUM_LT; LT_NZ] THEN
  SIMP_TAC[SUM_CONST; CARD_NUMSEG_1; FINITE_NUMSEG]);;

let MANGOLDT = prove
 (`!n. log(&(FACT n)) = sum(1..n) (\d. mangoldt(d) * floor(&n / &d))`,
  GEN_TAC THEN REWRITE_TAC[LOG_FACT] THEN MATCH_MP_TAC EQ_TRANS THEN
  EXISTS_TAC `sum(1..n) (\m. sum {d | d divides m} (\d. mangoldt d))` THEN
  SIMP_TAC[LOG_MANGOLDT_SUM; SUM_EQ_NUMSEG; LE_1] THEN
  MATCH_MP_TAC EQ_TRANS THEN
  EXISTS_TAC
   `sum (1..n) (\m. sum (1..n)
     (\d. mangoldt d * (if d divides m then &1 else &0)))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC SUM_EQ_NUMSEG THEN X_GEN_TAC `m:num` THEN
    STRIP_TAC THEN REWRITE_TAC[] THEN CONV_TAC SYM_CONV THEN
    MATCH_MP_TAC SUM_EQ_SUPERSET THEN
    ASM_SIMP_TAC[LE_1; FINITE_DIVISORS; IN_ELIM_THM; REAL_MUL_RZERO;
                 REAL_MUL_RID; SUBSET; IN_NUMSEG] THEN
    GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP DIVIDES_LE_STRONG) THEN
    ASM_ARITH_TAC;
    GEN_REWRITE_TAC LAND_CONV [SUM_SWAP_NUMSEG] THEN
    MATCH_MP_TAC SUM_EQ_NUMSEG THEN X_GEN_TAC `d:num` THEN
    ASM_SIMP_TAC[SUM_DIVISORS_FLOOR_LEMMA; LE_1; SUM_LMUL]]);;

(* ------------------------------------------------------------------------- *)
(* The Chebyshev psi function and the key bounds on it.                      *)
(* ------------------------------------------------------------------------- *)

let PSI_BOUND_INDUCT = prove
 (`!n. ~(n = 0)
       ==> sum(1..2*n) (\d. mangoldt(d)) -
           sum(1..n) (\d. mangoldt(d)) <= &9 * &n`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum (n+1..2 * n) (\d. mangoldt d)` THEN CONJ_TAC THENL
   [MATCH_MP_TAC REAL_EQ_IMP_LE THEN REWRITE_TAC[REAL_EQ_SUB_RADD] THEN
    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_UNION_EQ THEN
    ONCE_REWRITE_TAC[UNION_COMM] THEN REWRITE_TAC[FINITE_NUMSEG] THEN
    ASM_SIMP_TAC[NUMSEG_COMBINE_R; ARITH_RULE
     `~(n = 0) ==> 1 <= n + 1 /\ n <= 2 * n`] THEN
    REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY; IN_NUMSEG] THEN ARITH_TAC;
    ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
   `sum (n+1..2*n)
        (\d. mangoldt(d) * (floor(&(2 * n) / &d) - &2 * floor(&n / &d)))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `r:num` THEN STRIP_TAC THEN
    REWRITE_TAC[] THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_MUL_RID] THEN
    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[MANGOLDT_POS_LE] THEN
    MATCH_MP_TAC(REAL_ARITH `&1 <= a /\ b = &0 ==> &1 <= a - &2 * b`) THEN
    SUBGOAL_THEN `~(r = 0)` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
    ASM_SIMP_TAC[FLOOR_DIV_DIV; FLOOR_NUM; REAL_OF_NUM_LE; REAL_OF_NUM_EQ] THEN
    ASM_SIMP_TAC[DIV_EQ_0; LE_RDIV_EQ] THEN ASM_ARITH_TAC;
    ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
   `sum (1..2*n)
        (\d. mangoldt(d) * (floor(&(2 * n) / &d) - &2 * floor(&n / &d)))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC SUM_SUBSET THEN
    REWRITE_TAC[FINITE_NUMSEG; IN_DIFF; IN_NUMSEG] THEN
    CONJ_TAC THENL [ARITH_TAC; ALL_TAC] THEN
    X_GEN_TAC `r:num` THEN STRIP_TAC THEN
    SUBGOAL_THEN `~(r = 0)` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
    MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[MANGOLDT_POS_LE] THEN
    ASM_SIMP_TAC[FLOOR_DIV_DIV; REAL_NEG_SUB; REAL_SUB_LE] THEN
    ASM_SIMP_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_LE; MULT_DIV_LE];
    ALL_TAC] THEN
  REWRITE_TAC[REAL_ARITH `m * (f1 - &2 * f2) = m * f1 - &2 * m * f2`] THEN
  REWRITE_TAC[SUM_SUB_NUMSEG; SUM_LMUL] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum(1..2*n) (\d. mangoldt(d) * floor(&(2 * n) / &d)) -
              &2 * sum(1..n) (\d. mangoldt(d) * floor(&n / &d))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC(REAL_ARITH `y' <= y ==> x - y <= x - y'`) THEN
    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_POS] THEN
    MATCH_MP_TAC SUM_SUBSET THEN
    REWRITE_TAC[FINITE_NUMSEG; IN_DIFF; IN_NUMSEG] THEN
    SIMP_TAC[FLOOR_DIV_DIV; LE_1; FLOOR_NUM; REAL_LE_MUL; REAL_POS;
             MANGOLDT_POS_LE] THEN
    ARITH_TAC;
    ALL_TAC] THEN
  REWRITE_TAC[GSYM MANGOLDT] THEN
  MAP_EVERY (MP_TAC o C SPEC LOG_FACT_BOUNDS) [`n:num`; `2 * n`] THEN
  ASM_REWRITE_TAC[MULT_EQ_0; ARITH_EQ] THEN
  MATCH_MP_TAC(REAL_ARITH
    `a2 + e2 + &2 * (e1 - a1) <= m
     ==> abs(f2 - a2) <= e2 ==> abs(f1 - a1) <= e1 ==> f2 - &2 * f1 <= m`) THEN
  ASM_SIMP_TAC[GSYM REAL_OF_NUM_MUL; LOG_MUL; REAL_OF_NUM_LT; LT_NZ; ARITH] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC
   `&6 * log(&n) + (&2 * log(&2) - &1) * &1 + (&2 * log(&2)) * &n` THEN
  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `&6 * &n + (&2 * log(&2) - &1) * &n + (&2 * log(&2)) * &n` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC REAL_LE_ADD2 THEN
    ASM_SIMP_TAC[LOG_LE_REFL; REAL_LE_LMUL; REAL_POS; REAL_LE_RADD] THEN
    MATCH_MP_TAC REAL_LE_LMUL THEN
    ASM_REWRITE_TAC[REAL_OF_NUM_LE; ARITH_RULE `1 <= n <=> ~(n = 0)`];
    REWRITE_TAC[GSYM REAL_ADD_RDISTRIB] THEN
    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[REAL_POS]] THEN
  MP_TAC LOG_2_BOUNDS THEN REAL_ARITH_TAC);;

let PSI_BOUND_EXP = prove
 (`!n. sum(1..2 EXP n) (\d. mangoldt(d)) <= &9 * &(2 EXP n)`,
  INDUCT_TAC THEN
  SIMP_TAC[EXP; SUM_SING_NUMSEG; MANGOLDT_1; REAL_LE_MUL; REAL_POS] THEN
  REWRITE_TAC[GSYM REAL_OF_NUM_MUL] THEN
  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
   `s1 <= &9 * e ==> s2 - s1 <= &9 * e ==> s2 <= &9 * &2 * e`)) THEN
  MATCH_MP_TAC PSI_BOUND_INDUCT THEN
  REWRITE_TAC[EXP_EQ_0; ARITH]);;

let PSI_BOUND = prove
 (`!n. sum(1..n) (\d. mangoldt(d)) <= &18 * &n`,
  GEN_TAC THEN ASM_CASES_TAC `n <= 1` THENL
   [MATCH_MP_TAC REAL_LE_TRANS THEN
    EXISTS_TAC `sum(1..1) (\d. mangoldt d)` THEN CONJ_TAC THENL
     [MATCH_MP_TAC SUM_SUBSET; ALL_TAC] THEN
    REWRITE_TAC[SUM_SING_NUMSEG; FINITE_NUMSEG; IN_DIFF; IN_NUMSEG] THEN
    SIMP_TAC[MANGOLDT_POS_LE; MANGOLDT_1; REAL_LE_MUL; REAL_POS] THEN
    ASM_ARITH_TAC;
    ALL_TAC] THEN
  SUBGOAL_THEN `?k. n <= 2 EXP k /\ !l. l < k ==> ~(n <= 2 EXP l)`
  STRIP_ASSUME_TAC THENL
   [REWRITE_TAC[GSYM num_WOP] THEN EXISTS_TAC `n:num` THEN
    MP_TAC(SPEC `n:num` LT_POW2_REFL) THEN REWRITE_TAC[EXP] THEN ARITH_TAC;
    ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum(1..2 EXP k) (\d. mangoldt d)` THEN CONJ_TAC THENL
   [MATCH_MP_TAC SUM_SUBSET THEN
    REWRITE_TAC[FINITE_NUMSEG; IN_DIFF; IN_NUMSEG; MANGOLDT_POS_LE] THEN
    ASM_ARITH_TAC;
    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&9 * &(2 EXP k)` THEN
    REWRITE_TAC[PSI_BOUND_EXP] THEN
    ASM_CASES_TAC `k = 0` THENL
     [FIRST_X_ASSUM SUBST_ALL_TAC THEN ASM_ARITH_TAC; ALL_TAC] THEN
    FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
     `~(k = 0) ==> k = SUC(k - 1)`)) THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `k - 1`) THEN
    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
    REWRITE_TAC[REAL_OF_NUM_MUL; EXP; REAL_OF_NUM_LE] THEN ARITH_TAC]);;

(* ------------------------------------------------------------------------- *)
(* Now Mertens's first theorem.                                              *)
(* ------------------------------------------------------------------------- *)

let MERTENS_LEMMA = prove
 (`!n. ~(n = 0) ==> abs(sum(1..n) (\d. mangoldt(d) / &d) - log(&n)) <= &21`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN
  EXISTS_TAC `&n` THEN ASM_SIMP_TAC[REAL_OF_NUM_LT; LT_NZ] THEN
  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM REAL_ABS_NUM] THEN
  REWRITE_TAC[GSYM REAL_ABS_MUL; REAL_SUB_LDISTRIB; GSYM SUM_LMUL] THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP LOG_FACT_BOUNDS) THEN REWRITE_TAC[MANGOLDT] THEN
  MATCH_MP_TAC(REAL_ARITH
   `abs(n - &1) <= n /\ abs(s' - s) <= (k - &1) * n - a
    ==> abs(s' - (nl - n + &1)) <= a
        ==> abs(s - nl) <= n * k`) THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC(REAL_ARITH `&1 <= x ==> abs(x - &1) <= x`) THEN
    REWRITE_TAC[REAL_OF_NUM_LE] THEN ASM_ARITH_TAC;
    ALL_TAC] THEN
  REWRITE_TAC[GSYM SUM_SUB_NUMSEG] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
  ONCE_REWRITE_TAC[REAL_ARITH `n * i / x:real = i * n / x`] THEN
  REWRITE_TAC[GSYM REAL_SUB_LDISTRIB] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum(1..n) (\i. mangoldt i)` THEN CONJ_TAC THENL
   [MATCH_MP_TAC(REAL_ARITH `&0 <= --x /\ --x <= y ==> abs(x) <= y`) THEN
    REWRITE_TAC[GSYM SUM_NEG; REAL_ARITH
     `--(a * (x - y)):real = a * (y - x)`] THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC SUM_POS_LE_NUMSEG THEN SIMP_TAC[] THEN
      X_GEN_TAC `i:num` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL;
      MATCH_MP_TAC SUM_LE_NUMSEG THEN SIMP_TAC[] THEN
       X_GEN_TAC `i:num` THEN STRIP_TAC THEN
      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
      MATCH_MP_TAC REAL_LE_LMUL] THEN
    ASM_REWRITE_TAC[MANGOLDT_POS_LE; REAL_SUB_LE; REAL_LE_SUB_RADD] THEN
    MP_TAC(SPEC `&n / &i` FLOOR) THEN REAL_ARITH_TAC;
    ALL_TAC] THEN
  MATCH_MP_TAC(REAL_ARITH
   `x <= (k - &2) * n /\ l <= n ==> x <= k * n - &2 * l`) THEN
  ASM_SIMP_TAC[LOG_LE_REFL] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
  ASM_REWRITE_TAC[PSI_BOUND]);;

let MERTENS_MANGOLDT_VERSUS_LOG = prove
 (`!n s. s SUBSET (1..n)
         ==> abs (sum s (\d. mangoldt d / &d) -
                  sum {p | prime p /\ p IN s} (\p. log (&p) / &p)) <= &3`,
  REPEAT GEN_TAC THEN ASM_CASES_TAC `n = 0` THENL
   [ASM_REWRITE_TAC[NUMSEG_CLAUSES; ARITH; SUBSET_EMPTY] THEN
    DISCH_THEN SUBST_ALL_TAC THEN
    REWRITE_TAC[NOT_IN_EMPTY; EMPTY_GSPEC; SUM_CLAUSES] THEN REAL_ARITH_TAC;
    DISCH_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `abs(sum (1..n) (\d. mangoldt d / &d) -
                  sum {p | prime p /\ p IN 1..n} (\p. log (&p) / &p))` THEN
  CONJ_TAC THENL
   [SUBGOAL_THEN `FINITE(s:num->bool)` ASSUME_TAC THENL
     [ASM_MESON_TAC[FINITE_SUBSET; FINITE_NUMSEG]; ALL_TAC] THEN
    ONCE_REWRITE_TAC[CONJ_SYM] THEN
    ASM_SIMP_TAC[SUM_RESTRICT_SET; FINITE_NUMSEG] THEN
    ASM_SIMP_TAC[GSYM SUM_SUB; FINITE_NUMSEG] THEN
    MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= y ==> abs x <= abs y`) THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC SUM_POS_LE; MATCH_MP_TAC SUM_SUBSET_SIMPLE] THEN
    ASM_SIMP_TAC[IN_DIFF; FINITE_NUMSEG; REAL_SUB_LE] THEN
    X_GEN_TAC `x:num` THEN STRIP_TAC THEN COND_CASES_TAC THEN
    ASM_SIMP_TAC[REAL_LE_DIV; MANGOLDT_POS_LE; REAL_POS] THEN
    GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV) [GSYM EXP_1] THEN
    ASM_SIMP_TAC[MANGOLDT_PRIMEPOW; LE_REFL; REAL_LE_REFL];
    ALL_TAC] THEN
  SUBGOAL_THEN `{p | prime p /\ p IN 1..n} = {p | prime p /\ p <= n}`
  SUBST1_TAC THENL
   [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_NUMSEG] THEN
    MESON_TAC[ARITH_RULE `2 <= p ==> 1 <= p`; PRIME_GE_2];
    ALL_TAC] THEN
  SUBGOAL_THEN
   `sum(1..n) (\d. mangoldt d / &d) -
    sum {p | prime p /\ p <= n} (\p. log (&p) / &p) =
    sum {p EXP k | prime p /\ p EXP k <= n /\ k >= 2} (\d. mangoldt d / &d)`
  SUBST1_TAC THENL
   [SUBGOAL_THEN
     `sum {p | prime p /\ p <= n} (\p. log (&p) / &p) =
      sum {p | prime p /\ p <= n} (\d. mangoldt d / &d)`
    SUBST1_TAC THENL
     [MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[IN_ELIM_THM] THEN
      REPEAT STRIP_TAC THEN
      GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV) [GSYM EXP_1] THEN
      ASM_SIMP_TAC[MANGOLDT_PRIMEPOW; ARITH];
      ALL_TAC] THEN
    REWRITE_TAC[REAL_EQ_SUB_RADD] THEN MATCH_MP_TAC EQ_TRANS THEN
    EXISTS_TAC
     `sum {p EXP k | prime p /\ p EXP k <= n /\ k >= 1}
          (\d. mangoldt d / &d)` THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC SUM_SUPERSET THEN
      SIMP_TAC[IN_ELIM_THM; SUBSET; IN_NUMSEG] THEN
      CONJ_TAC THEN GEN_TAC THEN STRIP_TAC THEN
      ASM_REWRITE_TAC[ARITH_RULE `1 <= x <=> ~(x = 0)`; EXP_EQ_0] THENL
       [ASM_MESON_TAC[PRIME_0]; ALL_TAC] THEN
      REWRITE_TAC[real_div; REAL_ENTIRE] THEN DISJ1_TAC THEN
      REWRITE_TAC[mangoldt] THEN ASM_MESON_TAC[GE];
      ALL_TAC] THEN
    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_UNION_EQ THEN CONJ_TAC THENL
     [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `0..n` THEN
      REWRITE_TAC[SUBSET; IN_ELIM_THM; FINITE_NUMSEG; IN_NUMSEG; LE_0] THEN
      MESON_TAC[];
      ALL_TAC] THEN
    CONJ_TAC THENL
     [REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM; NOT_IN_EMPTY] THEN
      MESON_TAC[PRIME_EXP; ARITH_RULE `~(1 >= 2)`];
      REWRITE_TAC[ARITH_RULE `k >= 1 <=> k >= 2 \/ k = 1`] THEN
      REWRITE_TAC[EXTENSION; IN_UNION; IN_ELIM_THM] THEN MESON_TAC[EXP_1]];
    ALL_TAC] THEN
  MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= y ==> abs(x) <= y`) THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC SUM_POS_LE THEN
    SIMP_TAC[REAL_LE_DIV; REAL_POS; MANGOLDT_POS_LE]THEN
    MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `0..n` THEN
    REWRITE_TAC[SUBSET; IN_ELIM_THM; FINITE_NUMSEG; IN_NUMSEG; LE_0] THEN
    MESON_TAC[];
    ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC
   `sum {p | p IN 1..n /\ prime p}
        (\p. sum (2..n) (\k. log(&p) / &p pow k))` THEN
  CONJ_TAC THENL
   [SIMP_TAC[SUM_SUM_PRODUCT; FINITE_NUMSEG; FINITE_RESTRICT] THEN
    MATCH_MP_TAC SUM_LE_INCLUDED THEN EXISTS_TAC `\(p,k). p EXP k` THEN
    SIMP_TAC[FINITE_PRODUCT; FINITE_NUMSEG; FINITE_RESTRICT] THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `0..n` THEN
      REWRITE_TAC[SUBSET; IN_ELIM_THM; FINITE_NUMSEG; IN_NUMSEG; LE_0] THEN
      MESON_TAC[];
      ALL_TAC] THEN
    REWRITE_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM; EXISTS_PAIR_THM] THEN
    SIMP_TAC[IN_ELIM_THM; IN_NUMSEG; REAL_LE_DIV; REAL_POW_LE; REAL_POS;
             LOG_POS; REAL_OF_NUM_LE] THEN
    X_GEN_TAC `x:num` THEN
    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:num` THEN
    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN
    STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
    ASM_SIMP_TAC[MANGOLDT_PRIMEPOW; GSYM REAL_OF_NUM_POW; REAL_LE_REFL;
                 ARITH_RULE `k >= 2 ==> 1 <= k /\ 2 <= k`] THEN
    ASM_SIMP_TAC[PRIME_IMP_NZ; ARITH_RULE `1 <= k <=> ~(k = 0)`] THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `p EXP k` THEN ASM_SIMP_TAC[] THEN
      GEN_REWRITE_TAC LAND_CONV [GSYM EXP_1] THEN
      ASM_SIMP_TAC[PRIME_IMP_NZ; LE_EXP] THEN ASM_ARITH_TAC;
      MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `p EXP k` THEN ASM_SIMP_TAC[] THEN
      MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `2 EXP k` THEN
      ASM_SIMP_TAC[LT_POW2_REFL; LT_IMP_LE; EXP_MONO_LE; PRIME_GE_2]];
    ALL_TAC] THEN
  REWRITE_TAC[real_div; SUM_LMUL; GSYM REAL_POW_INV; SUM_GP] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum {p | p IN 1..n /\ prime p}
                  (\p. log(&p) / (&p * (&p - &1)))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC SUM_LE THEN SIMP_TAC[FINITE_NUMSEG; FINITE_RESTRICT] THEN
    X_GEN_TAC `p:num` THEN REWRITE_TAC[IN_ELIM_THM; IN_NUMSEG] THEN
    ASM_SIMP_TAC[REAL_INV_EQ_1; REAL_OF_NUM_EQ; PRIME_GE_2;
                 ARITH_RULE `2 <= p ==> ~(p = 1)`] THEN
    STRIP_TAC THEN COND_CASES_TAC THEN
    ASM_SIMP_TAC[REAL_MUL_RZERO; REAL_LE_DIV; REAL_LE_MUL; REAL_SUB_LE;
                 REAL_OF_NUM_LE; LOG_POS; LE_0] THEN
    REWRITE_TAC[real_div] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
    ASM_SIMP_TAC[LOG_POS; REAL_OF_NUM_LE] THEN
    MATCH_MP_TAC(REAL_ARITH
     `&0 <= y * z /\ x * z <= a ==> (x - y) * z <= a`) THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC REAL_LE_MUL THEN
      ASM_SIMP_TAC[REAL_POW_LE; REAL_LE_INV_EQ; REAL_POS; REAL_SUB_LE] THEN
      MATCH_MP_TAC REAL_INV_LE_1 THEN ASM_REWRITE_TAC[REAL_OF_NUM_LE];
      ALL_TAC] THEN
    MATCH_MP_TAC REAL_EQ_IMP_LE THEN
    FIRST_ASSUM(MP_TAC o MATCH_MP PRIME_GE_2) THEN
    REWRITE_TAC[GSYM REAL_OF_NUM_LE] THEN CONV_TAC REAL_FIELD;
    ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum (2..n)  (\p. log(&p) / (&p * (&p - &1)))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC SUM_SUBSET THEN SIMP_TAC[FINITE_NUMSEG; FINITE_RESTRICT] THEN
    REWRITE_TAC[IN_DIFF; IN_NUMSEG; IN_ELIM_THM] THEN
    CONJ_TAC THENL [MESON_TAC[PRIME_GE_2]; ALL_TAC] THEN
    ASM_SIMP_TAC[LOG_POS; REAL_OF_NUM_LE; ARITH_RULE `2 <= p ==> 1 <= p`;
                 REAL_LE_MUL; REAL_POS; REAL_SUB_LE; REAL_LE_DIV];
    ALL_TAC] THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `sum (2..n) (\m. log(&m) / (&m - &1) pow 2)` THEN CONJ_TAC THENL
   [MATCH_MP_TAC SUM_LE_NUMSEG THEN REPEAT STRIP_TAC THEN
    REWRITE_TAC[real_div] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
    ASM_SIMP_TAC[LOG_POS; REAL_OF_NUM_LE; ARITH_RULE `2 <= p ==> 1 <= p`] THEN
    MATCH_MP_TAC REAL_LE_INV2 THEN
    ASM_SIMP_TAC[REAL_POW_2; REAL_LE_RMUL_EQ; REAL_LT_MUL; REAL_LT_IMP_LE;
                 REAL_SUB_LT; REAL_OF_NUM_LT; ARITH_RULE `1 < p <=> 2 <= p`;
                 REAL_ARITH `x - &1 <= x`];
    ALL_TAC] THEN
  ASM_CASES_TAC `n < 2` THENL
   [RULE_ASSUM_TAC(REWRITE_RULE[GSYM NUMSEG_EMPTY]);
    RULE_ASSUM_TAC(REWRITE_RULE[NOT_LT])] THEN
  ASM_SIMP_TAC[SUM_CLAUSES] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
  ASM_SIMP_TAC[SUM_CLAUSES_LEFT; ARITH] THEN
  MATCH_MP_TAC(REAL_ARITH
    `x <= &1 /\ y <= e - &1 ==> x + y <= e`) THEN
  CONJ_TAC THENL [MP_TAC LOG_2_BOUNDS THEN REAL_ARITH_TAC; ALL_TAC] THEN
  ASM_CASES_TAC `n < 3` THENL
   [RULE_ASSUM_TAC(REWRITE_RULE[GSYM NUMSEG_EMPTY]);
    RULE_ASSUM_TAC(REWRITE_RULE[NOT_LT])] THEN
  ASM_SIMP_TAC[SUM_CLAUSES] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
  MP_TAC(ISPECL
   [`\z. clog(z) / (z - Cx(&1)) pow 2`;
    `\z. clog(z - Cx(&1)) - clog(z) - clog(z) / (z - Cx(&1))`;
    `3`; `n:num`] SUM_INTEGRAL_UBOUND_DECREASING) THEN
  ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN ANTS_TAC THENL
   [CONJ_TAC THENL
     [REWRITE_TAC[IN_SEGMENT_CX_GEN] THEN X_GEN_TAC `z:complex` THEN
      STRIP_TAC THENL
       [COMPLEX_DIFF_TAC THEN SIMP_TAC[COMPLEX_SUB_RZERO; COMPLEX_MUL_LID] THEN
        ASM_SIMP_TAC[RE_SUB; RE_CX; REAL_SUB_LT] THEN
        ASM_SIMP_TAC[REAL_ARITH `&2 <= x ==> &1 < x /\ &0 < x`] THEN
        SUBGOAL_THEN `~(z = Cx(&0)) /\ ~(z = Cx(&1))` MP_TAC THENL
         [ALL_TAC; CONV_TAC COMPLEX_FIELD] THEN
        REPEAT STRIP_TAC THEN UNDISCH_TAC `&2 <= Re z` THEN
        ASM_REWRITE_TAC[RE_CX] THEN REAL_ARITH_TAC;
        RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN
        ASM_ARITH_TAC];
      ALL_TAC] THEN
    MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN STRIP_TAC THEN
    MP_TAC(SPECL [`\z. clog(z) / (z - Cx(&1)) pow 2`;
                  `\z. inv(z * (z - Cx(&1)) pow 2) -
                       Cx(&2) * clog(z) / (z - Cx(&1)) pow 3`;
                  `Cx(x)`; `Cx(y)`] COMPLEX_MVT_LINE) THEN
    REWRITE_TAC[] THEN ANTS_TAC THENL
     [REWRITE_TAC[IN_SEGMENT_CX_GEN] THEN X_GEN_TAC `z:complex` THEN
      REWRITE_TAC[REAL_ARITH `a <= x /\ x <= b \/ b <= x /\ x <= a <=>
                         a <= x /\ x <= b \/ b < a /\ b <= x /\ x <= a`] THEN
      STRIP_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
      COMPLEX_DIFF_TAC THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN
      CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
      CONV_TAC NUM_REDUCE_CONV THEN
      SUBGOAL_THEN `~(z = Cx(&0)) /\ ~(z = Cx(&1))` MP_TAC THENL
       [ALL_TAC; CONV_TAC COMPLEX_FIELD] THEN
      CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
      REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[RE_CX; IM_CX] THEN
      REAL_ARITH_TAC;
      ALL_TAC] THEN
    GEN_REWRITE_TAC RAND_CONV [REAL_ARITH `x <= y <=> x - y <= &0`] THEN
    DISCH_THEN(X_CHOOSE_THEN `w:complex`
     (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
    REWRITE_TAC[GSYM CX_SUB; RE_MUL_CX] THEN
    REWRITE_TAC[REAL_ARITH `a * (y - x) <= &0 <=> &0 <= --a * (y - x)`] THEN
    MATCH_MP_TAC REAL_LE_MUL THEN ASM_REWRITE_TAC[REAL_SUB_LE] THEN
    REWRITE_TAC[RE_SUB; REAL_NEG_SUB; REAL_SUB_LE] THEN
    SUBGOAL_THEN `real w` ASSUME_TAC THENL
     [ASM_MESON_TAC[REAL_SEGMENT; REAL_CX]; ALL_TAC] THEN
    FIRST_X_ASSUM(SUBST_ALL_TAC o SYM o GEN_REWRITE_RULE I [REAL]) THEN
    ABBREV_TAC `u = Re w` THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT_CX]) THEN
    ASM_SIMP_TAC[REAL_ARITH
     `x <= y
      ==> (x <= u /\ u <= y \/ y <= u /\ u <= x <=> x <= u /\ u <= y)`] THEN
    STRIP_TAC THEN
    SUBGOAL_THEN `&0 < u /\ &1 < u /\ &2 <= u` STRIP_ASSUME_TAC THENL
     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
    ASM_SIMP_TAC[GSYM CX_LOG; GSYM CX_SUB; GSYM CX_POW; GSYM CX_DIV;
                 GSYM CX_MUL; GSYM CX_INV; RE_CX] THEN
    REWRITE_TAC[REAL_POW_2; real_div; REAL_INV_MUL; REAL_MUL_ASSOC;
                REAL_RING `(x:real) pow 3 = x * x pow 2`] THEN
    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_LT_INV_EQ; REAL_SUB_LT] THEN
    ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
    MATCH_MP_TAC(REAL_ARITH
     `a * b <= &1 /\ &1 / &2 <= c ==> b * a <= &2 * c`) THEN
    ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ] THEN
    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `log(&2)` THEN
    REWRITE_TAC[LOG_2_BOUNDS] THEN MATCH_MP_TAC LOG_MONO_LE_IMP THEN
    ASM_REAL_ARITH_TAC;
    ALL_TAC] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN
  MATCH_MP_TAC(REAL_ARITH `x = y /\ a <= b ==> x <= a ==> y <= b`) THEN
  CONJ_TAC THENL [MATCH_MP_TAC SUM_EQ_NUMSEG; ALL_TAC] THEN
  ASM_SIMP_TAC[GSYM CX_SUB; GSYM CX_LOG; GSYM CX_DIV; REAL_SUB_LT; ARITH;
      RE_CX; REAL_OF_NUM_LT; ARITH_RULE `3 <= n ==> 0 < n /\ 1 < n`;
      GSYM CX_POW] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN
  REWRITE_TAC[LOG_1; REAL_ARITH `a - (&0 - x - x / &1) = a + &2 * x`] THEN
  MATCH_MP_TAC(REAL_ARITH
   `a <= e - &2 /\ x <= &1 ==> a + &2 * x <= e`) THEN
  REWRITE_TAC[LOG_2_BOUNDS] THEN
  MATCH_MP_TAC(REAL_ARITH `a <= b /\ --c <= e ==> a - b - c <= e`) THEN
  REWRITE_TAC[REAL_SUB_REFL; REAL_ARITH `--x <= &0 <=> &0 <= x`] THEN
  ASM_SIMP_TAC[REAL_LE_DIV; REAL_SUB_LE; LOG_POS; REAL_OF_NUM_LE;
    REAL_OF_NUM_LT; LOG_MONO_LE_IMP; REAL_ARITH `x - &1 <= x`; REAL_SUB_LT;
    LE_0; ARITH_RULE `3 <= n ==> 1 <= n /\ 1 < n`]);;

let MERTENS = prove
 (`!n. ~(n = 0)
       ==> abs(sum {p | prime p /\ p <= n}
                   (\p. log(&p) / &p) - log(&n)) <= &24`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP MERTENS_LEMMA) THEN
  MATCH_MP_TAC(REAL_ARITH
   `abs(s1 - s2) <= k - e ==> abs(s1 - l) <= e ==> abs(s2 - l) <= k`) THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN
  SUBGOAL_THEN `{p | prime p /\ p <= n} = {p | prime p /\ p IN 1..n}`
  SUBST1_TAC THENL
   [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_NUMSEG] THEN
    MESON_TAC[ARITH_RULE `2 <= p ==> 1 <= p`; PRIME_GE_2];
    MATCH_MP_TAC MERTENS_MANGOLDT_VERSUS_LOG THEN
    EXISTS_TAC `n:num` THEN ASM_REWRITE_TAC[SUBSET_REFL]]);;
