(* This file is generated by Why3's Coq driver *)
(* Beware! Only edit allowed sections below    *)
Require Import BuiltIn.
Require BuiltIn.
Require int.Int.
Require int.Abs.
Require int.EuclideanDivision.
Require int.ComputerDivision.
Require number.Parity.
Require number.Divisibility.
Require number.Prime.
Require map.Map.

(* Why3 assumption *)
Definition unit := unit.

Axiom qtmark : Type.
Parameter qtmark_WhyType : WhyType qtmark.
Existing Instance qtmark_WhyType.

(* Why3 assumption *)
Definition lt_nat (x:Z) (y:Z): Prop := (0%Z <= y)%Z /\ (x < y)%Z.

(* Why3 assumption *)
Inductive lex: (Z* Z)%type -> (Z* Z)%type -> Prop :=
  | Lex_1 : forall (x1:Z) (x2:Z) (y1:Z) (y2:Z), (lt_nat x1 x2) -> (lex (x1,
      y1) (x2, y2))
  | Lex_2 : forall (x:Z) (y1:Z) (y2:Z), (lt_nat y1 y2) -> (lex (x, y1) (x,
      y2)).

(* Why3 assumption *)
Inductive ref (a:Type) :=
  | mk_ref : a -> ref a.
Axiom ref_WhyType : forall (a:Type) {a_WT:WhyType a}, WhyType (ref a).
Existing Instance ref_WhyType.
Implicit Arguments mk_ref [[a]].

(* Why3 assumption *)
Definition contents {a:Type} {a_WT:WhyType a} (v:(ref a)): a :=
  match v with
  | (mk_ref x) => x
  end.

(* Why3 assumption *)
Inductive array (a:Type) :=
  | mk_array : Z -> (map.Map.map Z a) -> array a.
Axiom array_WhyType : forall (a:Type) {a_WT:WhyType a}, WhyType (array a).
Existing Instance array_WhyType.
Implicit Arguments mk_array [[a]].

(* Why3 assumption *)
Definition elts {a:Type} {a_WT:WhyType a} (v:(array a)): (map.Map.map Z a) :=
  match v with
  | (mk_array x x1) => x1
  end.

(* Why3 assumption *)
Definition length {a:Type} {a_WT:WhyType a} (v:(array a)): Z :=
  match v with
  | (mk_array x x1) => x
  end.

(* Why3 assumption *)
Definition get {a:Type} {a_WT:WhyType a} (a1:(array a)) (i:Z): a :=
  (map.Map.get (elts a1) i).

(* Why3 assumption *)
Definition set {a:Type} {a_WT:WhyType a} (a1:(array a)) (i:Z) (v:a): (array
  a) := (mk_array (length a1) (map.Map.set (elts a1) i v)).

(* Why3 assumption *)
Definition no_prime_in (l:Z) (u:Z): Prop := forall (x:Z), ((l < x)%Z /\
  (x < u)%Z) -> ~ (number.Prime.prime x).

(* Why3 assumption *)
Definition first_primes (p:(array Z)) (u:Z): Prop := ((get p 0%Z) = 2%Z) /\
  ((forall (i:Z) (j:Z), ((0%Z <= i)%Z /\ ((i < j)%Z /\ (j < u)%Z)) -> ((get p
  i) < (get p j))%Z) /\ ((forall (i:Z), ((0%Z <= i)%Z /\ (i < u)%Z) ->
  (number.Prime.prime (get p i))) /\ forall (i:Z), ((0%Z <= i)%Z /\
  (i < (u - 1%Z)%Z)%Z) -> (no_prime_in (get p i) (get p (i + 1%Z)%Z)))).

Axiom exists_prime : forall (p:(array Z)) (u:Z), (1%Z <= u)%Z ->
  ((first_primes p u) -> forall (d:Z), ((2%Z <= d)%Z /\ (d <= (get p
  (u - 1%Z)%Z))%Z) -> ((number.Prime.prime d) -> exists i:Z, ((0%Z <= i)%Z /\
  (i < u)%Z) /\ (d = (get p i)))).

Axiom Bertrand_postulate : forall (p:Z), (number.Prime.prime p) ->
  ~ (no_prime_in p (2%Z * p)%Z).

Import Zquot.

(* Why3 goal *)
Theorem WP_parameter_prime_numbers : forall (m:Z), (2%Z <= m)%Z ->
  ((0%Z <= m)%Z -> forall (p:Z) (p1:(map.Map.map Z Z)), ((0%Z <= p)%Z /\
  ((p = m) /\ forall (i:Z), ((0%Z <= i)%Z /\ (i < m)%Z) -> ((map.Map.get p1
  i) = 0%Z))) -> (((0%Z <= 0%Z)%Z /\ (0%Z < p)%Z) -> forall (p2:(map.Map.map
  Z Z)), ((0%Z <= p)%Z /\ (p2 = (map.Map.set p1 0%Z 2%Z))) ->
  (((0%Z <= 1%Z)%Z /\ (1%Z < p)%Z) -> forall (p3:(map.Map.map Z Z)),
  ((0%Z <= p)%Z /\ (p3 = (map.Map.set p2 1%Z 3%Z))) -> let o :=
  (m - 1%Z)%Z in ((2%Z <= o)%Z -> forall (n:Z) (p4:(map.Map.map Z Z)),
  forall (j:Z), ((2%Z <= j)%Z /\ (j <= o)%Z) -> (((first_primes (mk_array p
  p4) j) /\ ((((map.Map.get p4 (j - 1%Z)%Z) < n)%Z /\
  (n < (2%Z * (map.Map.get p4 (j - 1%Z)%Z))%Z)%Z) /\ ((number.Parity.odd
  n) /\ (no_prime_in (map.Map.get p4 (j - 1%Z)%Z) n)))) -> forall (k:Z),
  forall (n1:Z) (p5:(map.Map.map Z Z)), ((0%Z <= p)%Z /\ (((1%Z <= k)%Z /\
  (k < j)%Z) /\ ((first_primes (mk_array p p5) j) /\ ((((map.Map.get p5
  (j - 1%Z)%Z) < n1)%Z /\ (n1 < (2%Z * (map.Map.get p5 (j - 1%Z)%Z))%Z)%Z) /\
  ((number.Parity.odd n1) /\ ((no_prime_in (map.Map.get p5 (j - 1%Z)%Z)
  n1) /\ forall (i:Z), ((0%Z <= i)%Z /\ (i < k)%Z) ->
  ~ (number.Divisibility.divides (map.Map.get p5 i) n1))))))) ->
  (((0%Z <= k)%Z /\ (k < p)%Z) ->
  ((~ ((ZArith.BinInt.Z.rem n1 (map.Map.get p5 k)) = 0%Z)) ->
  (((0%Z <= k)%Z /\ (k < p)%Z) -> (((0%Z <= k)%Z /\ (k < p)%Z) ->
  (((map.Map.get p5 k) < (ZArith.BinInt.Z.quot n1 (map.Map.get p5 k)))%Z ->
  ((k + 1%Z)%Z < j)%Z)))))))))).
intros m h1 h2 p p1 (h3,(h4,h5)) (h6,h7) p2 (h8,h9) (h10,h11) p3 (h12,h13) o
h14 n p4 j (h15,h16) (h17,((h18,h19),(h20,h21))) k n1 p5
(h22,((h23,h24),(h25,((h26,h27),(h28,(h29,h30)))))) (h31,h32) h33 (h34,h35)
(h36,h37) h38.
assert (case: (k = j-1 \/ k+1<j)%Z) by omega. destruct case. 2: auto.
apply False_ind.
subst k.
assert (2 < Map.get p5 (j-1))%Z.
red in h25. destruct h25 as (hh1, (hh2, _)).
rewrite <- hh1. apply hh2; omega.
generalize (Z_quot_rem_eq n1 (Map.get p5 (j-1))%Z). intro div.
assert (ne1: (0 <= n1 /\ Map.get p5 (j-1) <> 0)%Z) by omega.
assert (mod_: (0 <= Z.rem n1 (Map.get p5 (j-1)))%Z).
destruct (not_Zeq_inf _ _ (proj2 ne1)) as [Zm|Zm].
now apply Zrem_lt_pos_neg.
now apply Zrem_lt_pos_pos.
assert (n1 > Map.get p5 (j - 1) * Map.get p5 (j-1))%Z.
assert (Map.get p5 (j - 1) * (Z.quot n1 (Map.get p5 (j - 1))) > Map.get p5 (j - 1) * Map.get p5 (j-1))%Z.
apply Zmult_gt_compat_l.
omega.
apply Zlt_gt.
assumption.
omega.
assert (n1 < Map.get p5 (j - 1) * Map.get p5 (j - 1))%Z.
assert (2 * Map.get p5 (j - 1) < Map.get p5 (j - 1) * Map.get p5 (j - 1))%Z.
apply Zmult_lt_compat_r; omega.
omega.
omega.
Qed.

