(* This file is generated by Why3's Coq 8.4 driver *)
(* Beware! Only edit allowed sections below    *)
Require Import BuiltIn.
Require BuiltIn.
Require int.Int.
Require map.Map.
Require map.MapPermut.

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

(* Why3 assumption *)
Inductive ref (a:Type) {a_WT:WhyType a} :=
  | 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] [a_WT]].

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

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

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

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

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

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

(* Why3 assumption *)
Definition make {a:Type} {a_WT:WhyType a} (n:Z) (v:a): (@array a a_WT) :=
  (mk_array n (map.Map.const v:(@map.Map.map Z _ a a_WT))).

(* Why3 assumption *)
Definition map_eq_sub {a:Type} {a_WT:WhyType a} (a1:(@map.Map.map Z _
  a a_WT)) (a2:(@map.Map.map Z _ a a_WT)) (l:Z) (u:Z): Prop := forall (i:Z),
  ((l <= i)%Z /\ (i < u)%Z) -> ((map.Map.get a1 i) = (map.Map.get a2 i)).

(* Why3 assumption *)
Definition array_eq_sub {a:Type} {a_WT:WhyType a} (a1:(@array a a_WT))
  (a2:(@array a a_WT)) (l:Z) (u:Z): Prop := ((length a1) = (length a2)) /\
  (((0%Z <= l)%Z /\ (l <= (length a1))%Z) /\ (((0%Z <= u)%Z /\
  (u <= (length a1))%Z) /\ (map_eq_sub (elts a1) (elts a2) l u))).

(* Why3 assumption *)
Definition array_eq {a:Type} {a_WT:WhyType a} (a1:(@array a a_WT))
  (a2:(@array a a_WT)): Prop := ((length a1) = (length a2)) /\ (map_eq_sub
  (elts a1) (elts a2) 0%Z (length a1)).

(* Why3 assumption *)
Definition exchange {a:Type} {a_WT:WhyType a} (a1:(@array a a_WT))
  (a2:(@array a a_WT)) (i:Z) (j:Z): Prop := ((length a1) = (length a2)) /\
  (map.MapPermut.exchange (elts a1) (elts a2) 0%Z (length a1) i j).

(* Why3 assumption *)
Definition permut {a:Type} {a_WT:WhyType a} (a1:(@array a a_WT)) (a2:(@array
  a a_WT)) (l:Z) (u:Z): Prop := ((length a1) = (length a2)) /\
  (((0%Z <= l)%Z /\ (l <= (length a1))%Z) /\ (((0%Z <= u)%Z /\
  (u <= (length a1))%Z) /\ (map.MapPermut.permut (elts a1) (elts a2) l u))).

(* Why3 assumption *)
Definition permut_sub {a:Type} {a_WT:WhyType a} (a1:(@array a a_WT))
  (a2:(@array a a_WT)) (l:Z) (u:Z): Prop := (map_eq_sub (elts a1) (elts a2)
  0%Z l) /\ ((permut a1 a2 l u) /\ (map_eq_sub (elts a1) (elts a2) u
  (length a1))).

(* Why3 assumption *)
Definition permut_all {a:Type} {a_WT:WhyType a} (a1:(@array a a_WT))
  (a2:(@array a a_WT)): Prop := ((length a1) = (length a2)) /\
  (map.MapPermut.permut (elts a1) (elts a2) 0%Z (length a1)).

Axiom permut_sub_refl : forall {a:Type} {a_WT:WhyType a}, forall (a1:(@array
  a a_WT)) (l:Z) (u:Z), ((0%Z <= l)%Z /\ ((l <= u)%Z /\
  (u <= (length a1))%Z)) -> (permut_sub a1 a1 l u).

Axiom permut_sub_trans : forall {a:Type} {a_WT:WhyType a}, forall (a1:(@array
  a a_WT)) (a2:(@array a a_WT)) (a3:(@array a a_WT)) (l:Z) (u:Z), (permut_sub
  a1 a2 l u) -> ((permut_sub a2 a3 l u) -> (permut_sub a1 a3 l u)).

Axiom exchange_permut_sub : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)) (i:Z) (j:Z) (l:Z) (u:Z),
  (exchange a1 a2 i j) -> (((l <= i)%Z /\ (i < u)%Z) -> (((l <= j)%Z /\
  (j < u)%Z) -> ((0%Z <= l)%Z -> ((u <= (length a1))%Z -> (permut_sub a1 a2 l
  u))))).

Axiom permut_sub_unmodified : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)) (l:Z) (u:Z), (permut_sub
  a1 a2 l u) -> forall (i:Z), (((0%Z <= i)%Z /\ (i < l)%Z) \/ ((u <= i)%Z /\
  (i < (length a1))%Z)) -> ((get a2 i) = (get a1 i)).

Axiom permut_sub_weakening : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)) (l1:Z) (u1:Z) (l2:Z)
  (u2:Z), (permut_sub a1 a2 l1 u1) -> (((0%Z <= l2)%Z /\ (l2 <= l1)%Z) ->
  (((u1 <= u2)%Z /\ (u2 <= (length a1))%Z) -> (permut_sub a1 a2 l2 u2))).

Axiom permut_sub_compose : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)) (a3:(@array a a_WT))
  (l1:Z) (u1:Z) (l2:Z) (u2:Z), (u1 <= l2)%Z -> ((permut_sub a1 a2 l1 u1) ->
  ((permut_sub a2 a3 l2 u2) -> (permut_sub a1 a3 l1 u2))).

Axiom permut_all_refl : forall {a:Type} {a_WT:WhyType a}, forall (a1:(@array
  a a_WT)), (permut_all a1 a1).

Axiom permut_all_trans : forall {a:Type} {a_WT:WhyType a}, forall (a1:(@array
  a a_WT)) (a2:(@array a a_WT)) (a3:(@array a a_WT)), (permut_all a1 a2) ->
  ((permut_all a2 a3) -> (permut_all a1 a3)).

Axiom exchange_permut_all : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)) (i:Z) (j:Z), (exchange a1
  a2 i j) -> (permut_all a1 a2).

Axiom array_eq_permut_all : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)), (array_eq a1 a2) ->
  (permut_all a1 a2).

Axiom permut_sub_permut_all : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(@array a a_WT)) (a2:(@array a a_WT)) (l:Z) (u:Z), (permut_sub
  a1 a2 l u) -> (permut_all a1 a2).

Parameter usN: Z.

Parameter f: Z.

Axiom f_N_range : (1%Z <= f)%Z /\ (f <= usN)%Z.

(* Why3 assumption *)
Definition found (a:(@array Z _)): Prop := forall (p:Z) (q:Z),
  ((1%Z <= p)%Z /\ ((p <= f)%Z /\ ((f <= q)%Z /\ (q <= usN)%Z))) -> (((get a
  p) <= (get a f))%Z /\ ((get a f) <= (get a q))%Z).

(* Why3 assumption *)
Definition m_invariant (m:Z) (a:(@array Z _)): Prop := (m <= f)%Z /\
  forall (p:Z) (q:Z), ((1%Z <= p)%Z /\ ((p < m)%Z /\ ((m <= q)%Z /\
  (q <= usN)%Z))) -> ((get a p) <= (get a q))%Z.

(* Why3 assumption *)
Definition n_invariant (n:Z) (a:(@array Z _)): Prop := (f <= n)%Z /\
  forall (p:Z) (q:Z), ((1%Z <= p)%Z /\ ((p <= n)%Z /\ ((n < q)%Z /\
  (q <= usN)%Z))) -> ((get a p) <= (get a q))%Z.

(* Why3 assumption *)
Definition i_invariant (m:Z) (n:Z) (i:Z) (r:Z) (a:(@array Z _)): Prop :=
  (m <= i)%Z /\ ((forall (p:Z), ((1%Z <= p)%Z /\ (p < i)%Z) -> ((get a
  p) <= r)%Z) /\ ((i <= n)%Z -> exists p:Z, ((i <= p)%Z /\ (p <= n)%Z) /\
  (r <= (get a p))%Z)).

(* Why3 assumption *)
Definition j_invariant (m:Z) (n:Z) (j:Z) (r:Z) (a:(@array Z _)): Prop :=
  (j <= n)%Z /\ ((forall (q:Z), ((j < q)%Z /\ (q <= usN)%Z) -> (r <= (get a
  q))%Z) /\ ((m <= j)%Z -> exists q:Z, ((m <= q)%Z /\ (q <= j)%Z) /\ ((get a
  q) <= r)%Z)).

(* Why3 assumption *)
Definition termination (i:Z) (j:Z) (i0:Z) (j0:Z) (r:Z) (a:(@array
  Z _)): Prop := ((i0 < i)%Z /\ (j < j0)%Z) \/ (((i <= f)%Z /\ (f <= j)%Z) /\
  ((get a f) = r)).


(* Why3 goal *)
Theorem WP_parameter_find : forall (a:Z) (a1:(@map.Map.map Z _ Z _)),
  let a2 := (mk_array a a1) in (((0%Z <= a)%Z /\ (a = (usN + 1%Z)%Z)) ->
  forall (n:Z) (m:Z) (a3:(@map.Map.map Z _ Z _)), let a4 := (mk_array a
  a3) in (((m_invariant m a4) /\ ((n_invariant n a4) /\ ((permut_all a4
  a2) /\ ((1%Z <= m)%Z /\ (n <= usN)%Z)))) -> ((m < n)%Z -> let o := f in
  (((0%Z <= a)%Z /\ ((0%Z <= o)%Z /\ (o < a)%Z)) -> let r := (map.Map.get a3
  o) in forall (j:Z) (i:Z) (a5:(@map.Map.map Z _ Z _)), let a6 := (mk_array a
  a5) in (((i_invariant m n i r a6) /\ ((j_invariant m n j r a6) /\
  ((m_invariant m a6) /\ ((n_invariant n a6) /\ ((0%Z <= j)%Z /\
  ((i <= (usN + 1%Z)%Z)%Z /\ ((termination i j m n r a6) /\ (permut_all a6
  a2)))))))) -> ((i <= j)%Z -> forall (i1:Z), ((i_invariant m n i1 r a6) /\
  (((i <= i1)%Z /\ (i1 <= n)%Z) /\ (termination i1 j m n r a6))) ->
  (((0%Z <= a)%Z /\ ((0%Z <= i1)%Z /\ (i1 < a)%Z)) -> ((~ ((map.Map.get a5
  i1) < r)%Z) -> forall (j1:Z), ((j_invariant m n j1 r a6) /\ ((j1 <= j)%Z /\
  ((m <= j1)%Z /\ (termination i1 j1 m n r a6)))) -> (((0%Z <= j1)%Z /\
  (j1 < a)%Z) -> ((~ (r < (map.Map.get a5 j1))%Z) -> ((((map.Map.get a5
  j1) <= r)%Z /\ (r <= (map.Map.get a5 i1))%Z) -> ((i1 <= j1)%Z ->
  (((0%Z <= i1)%Z /\ (i1 < a)%Z) -> (((0%Z <= j1)%Z /\ (j1 < a)%Z) ->
  (((0%Z <= i1)%Z /\ (i1 < a)%Z) -> forall (a7:(@map.Map.map Z _ Z _)),
  ((0%Z <= a)%Z /\ (a7 = (map.Map.set a5 i1 (map.Map.get a5 j1)))) ->
  (((0%Z <= j1)%Z /\ (j1 < a)%Z) -> forall (a8:(@map.Map.map Z _ Z _)),
  let a9 := (mk_array a a8) in (((0%Z <= a)%Z /\ (a8 = (map.Map.set a7 j1
  (map.Map.get a5 i1)))) -> ((exchange a9 a6 i1 j1) -> (((map.Map.get a8
  i1) <= r)%Z -> ((r <= (map.Map.get a8 j1))%Z -> forall (i2:Z),
  (i2 = (i1 + 1%Z)%Z) -> forall (j2:Z), (j2 = (j1 - 1%Z)%Z) -> ((i_invariant
  m n i2 r a9) /\ ((j_invariant m n j2 r a9) /\ ((m_invariant m a9) /\
  ((n_invariant n a9) /\ ((0%Z <= j2)%Z /\ ((i2 <= (usN + 1%Z)%Z)%Z /\
  ((termination i2 j2 m n r a9) /\ (permut_all a9
  a2)))))))))))))))))))))))))))).
(* Why3 intros a a1 a2 (h1,h2) n m a3 a4 (h3,(h4,(h5,(h6,h7)))) h8 o
        (h9,(h10,h11)) r j i a5 a6
        (h12,(h13,(h14,(h15,(h16,(h17,(h18,h19))))))) h20 i1
        (h21,((h22,h23),h24)) (h25,(h26,h27)) h28 j1 (h29,(h30,(h31,h32)))
        (h33,h34) h35 (h36,h37) h38 (h39,h40) (h41,h42) (h43,h44) a7
        (h45,h46) (h47,h48) a8 a9 (h49,h50) h51 h52 h53 i2 h54 j2 h55. *)
(* intros a a1 a2 (h1,h2) n m a3 a4 (h3,(h4,(h5,(h6,h7)))) h8 (h9,(h10,h11))
   r j i a5 a6 (h12,(h13,(h14,(h15,(h16,(h17,(h18,h19))))))) h20 i1
   (h21,((h22,h23),h24)) (h25,(h26,h27)) h28 j1 (h29,(h30,(h31,h32)))
   (h33,h34) h35 (h36,h37) h38 (h39,h40) (h41,h42) (h43,h44) a7 (h45,h46)
   (h47,h48) a8 a9 (h49,h50) h51 h52 h53 i2 h54 j2 h55. *)
(* YOU MAY EDIT THE PROOF BELOW *)
intuition.
intuition.
(* i_invariant *)
red; intuition.
red in H22. intuition.
unfold get; simpl.
assert (h: (p < i1 \/ p = i1)%Z) by omega.
destruct h.
subst a8.
rewrite Map.Select_neq; try omega.
subst a7.
rewrite Map.Select_neq; try omega.
red in H22.
unfold get in H22; simpl in H22. intuition.
subst p a8.
assert (h: (i1 = j1 \/ i1 <> j1)%Z) by omega.
destruct h.
subst i1.
rewrite Map.Select_eq; try omega.
rewrite Map.Select_neq; try omega.
subst a7.
rewrite Map.Select_eq; try omega.
unfold get; simpl.
red in H22; unfold get in H22; simpl in H22; intuition.
assert (h: (i1 < j1 \/ i1 = j1)%Z) by omega. destruct h.
exists j1.
split. red in H35; omega.
subst a8; rewrite Map.Select_eq; try omega.
assert (h: (j1 < n)%Z) by omega.
exists (j1+1)%Z.
split. omega.
red in H35; unfold get in H35. simpl in H35; intuition.
subst a8; rewrite Map.Select_neq; try omega.
subst a7; rewrite Map.Select_neq; try omega.
apply H35; omega.
(* j_invariant *)
red; intuition.
red in H35; intuition.
unfold get; simpl.
assert (h: (j1 < q \/ q = j1)%Z) by omega.
destruct h.
subst a8.
rewrite Map.Select_neq; try omega.
subst a7.
rewrite Map.Select_neq; try omega.
red in H35.
unfold get in H35; simpl in H35. intuition.
subst q a8.
assert (h: (i1 = j1 \/ i1 <> j1)%Z) by omega.
destruct h.
subst i1.
rewrite Map.Select_eq; try omega.
rewrite Map.Select_eq; try omega.
assert (h: (i1 < j1 \/ i1 = j1)%Z) by omega. destruct h.
exists i1.
split. red in H22; omega.
unfold get; simpl.
subst a8; rewrite Map.Select_neq; try omega.
subst a7; rewrite Map.Select_eq; try omega.
assert (h: (m < i1)%Z) by omega.
exists (i1-1)%Z.
split. omega.
red in H22; unfold get in H22. simpl in H22; intuition.
unfold get; simpl.
subst a8; rewrite Map.Select_neq; try omega.
subst a7; rewrite Map.Select_neq; try omega.
apply H22; omega.
(* m_invariant *)
(*clear H15 H23 H40.*)
red; intuition.
red in H13; omega.
unfold get; simpl.
red in H13; intuition.
unfold get in H52; simpl in H52.
subst a8.
rewrite Map.Select_neq at 1; try omega.
subst a7.
rewrite Map.Select_neq at 1; red in H22; try omega.
assert (h: (q = i1 \/ q <> i1)%Z) by omega. destruct h.
subst q.
assert (h: (i1 = j1 \/ i1 <> j1)%Z) by omega. destruct h.
subst i1.
rewrite Map.Select_eq; try omega.
apply H59; omega.
rewrite Map.Select_neq; try omega.
rewrite Map.Select_eq; try omega.
apply H59; omega.
assert (h: (q = j1 \/ q <> j1)%Z) by omega. destruct h.
subst q.
rewrite Map.Select_eq; try omega.
apply H59; omega.
rewrite Map.Select_neq; try omega.
rewrite Map.Select_neq; try omega.
apply H59; omega.
(* n_invariant *)
(*clear H15 H23 H40.*)
red; intuition.
red in H14; omega.
unfold get; simpl.
red in H14; intuition.
unfold get in H59; simpl in H59.
subst a8.
rewrite (Map.Select_neq _ _ q); red in H35; try omega.
subst a7.
rewrite (Map.Select_neq _ _ q); try omega.
assert (h: (p = i1 \/ p <> i1)%Z) by omega. destruct h.
subst p.
assert (h: (i1 = j1 \/ i1 <> j1)%Z) by omega. destruct h.
subst i1.
rewrite Map.Select_eq; try omega.
apply H59; omega.
rewrite Map.Select_neq; try omega.
rewrite Map.Select_eq; try omega.
apply H59; omega.
assert (h: (p = j1 \/ p <> j1)%Z) by omega. destruct h.
subst p.
rewrite Map.Select_eq; try omega.
apply H59; red in H22; omega.
rewrite Map.Select_neq; try omega.
rewrite Map.Select_neq; try omega.
apply H59; omega.
(* termination *)
red; intros.
unfold get; simpl.
red in H22.
red in H35.
left.
intuition.
(* permut *)
red; simpl.
split. trivial.
apply MapPermut.permut_trans with a5.
assert (permut_all (mk_array a a8) (mk_array a a5)).
  apply exchange_permut_all with i1 j1; auto.
  destruct H54; intuition.
red in H19; intuition.
Qed.

