(* 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.MinMax.
Require map.Map.

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

Axiom bag : forall (a:Type) {a_WT:WhyType a}, Type.
Parameter bag_WhyType : forall (a:Type) {a_WT:WhyType a}, WhyType (bag a).
Existing Instance bag_WhyType.

Parameter nb_occ: forall {a:Type} {a_WT:WhyType a}, a -> (bag a) -> Z.

Axiom occ_non_negative : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a))
  (x:a), (0%Z <= (nb_occ x b))%Z.

(* Why3 assumption *)
Definition mem {a:Type} {a_WT:WhyType a}(x:a) (b:(bag a)): Prop :=
  (0%Z < (nb_occ x b))%Z.

(* Why3 assumption *)
Definition eq_bag {a:Type} {a_WT:WhyType a}(a1:(bag a)) (b:(bag a)): Prop :=
  forall (x:a), ((nb_occ x a1) = (nb_occ x b)).

Axiom bag_extensionality : forall {a:Type} {a_WT:WhyType a}, forall (a1:(bag
  a)) (b:(bag a)), (eq_bag a1 b) -> (a1 = b).

Parameter empty_bag: forall {a:Type} {a_WT:WhyType a}, (bag a).

Axiom occ_empty : forall {a:Type} {a_WT:WhyType a}, forall (x:a), ((nb_occ x
  (empty_bag :(bag a))) = 0%Z).

Axiom is_empty : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a)),
  (forall (x:a), ((nb_occ x b) = 0%Z)) -> (b = (empty_bag :(bag a))).

Parameter singleton: forall {a:Type} {a_WT:WhyType a}, a -> (bag a).

Axiom occ_singleton : forall {a:Type} {a_WT:WhyType a}, forall (x:a) (y:a),
  ((x = y) /\ ((nb_occ y (singleton x)) = 1%Z)) \/ ((~ (x = y)) /\ ((nb_occ y
  (singleton x)) = 0%Z)).

Axiom occ_singleton_eq : forall {a:Type} {a_WT:WhyType a}, forall (x:a)
  (y:a), (x = y) -> ((nb_occ y (singleton x)) = 1%Z).

Axiom occ_singleton_neq : forall {a:Type} {a_WT:WhyType a}, forall (x:a)
  (y:a), (~ (x = y)) -> ((nb_occ y (singleton x)) = 0%Z).

Parameter union: forall {a:Type} {a_WT:WhyType a}, (bag a) -> (bag a) -> (bag
  a).

Axiom occ_union : forall {a:Type} {a_WT:WhyType a}, forall (x:a) (a1:(bag a))
  (b:(bag a)), ((nb_occ x (union a1 b)) = ((nb_occ x a1) + (nb_occ x b))%Z).

Axiom Union_comm : forall {a:Type} {a_WT:WhyType a}, forall (a1:(bag a))
  (b:(bag a)), ((union a1 b) = (union b a1)).

Axiom Union_identity : forall {a:Type} {a_WT:WhyType a}, forall (a1:(bag a)),
  ((union a1 (empty_bag :(bag a))) = a1).

Axiom Union_assoc : forall {a:Type} {a_WT:WhyType a}, forall (a1:(bag a))
  (b:(bag a)) (c:(bag a)), ((union a1 (union b c)) = (union (union a1 b) c)).

Axiom bag_simpl : forall {a:Type} {a_WT:WhyType a}, forall (a1:(bag a))
  (b:(bag a)) (c:(bag a)), ((union a1 b) = (union c b)) -> (a1 = c).

Axiom bag_simpl_left : forall {a:Type} {a_WT:WhyType a}, forall (a1:(bag a))
  (b:(bag a)) (c:(bag a)), ((union a1 b) = (union a1 c)) -> (b = c).

(* Why3 assumption *)
Definition add {a:Type} {a_WT:WhyType a}(x:a) (b:(bag a)): (bag a) :=
  (union (singleton x) b).

Axiom occ_add_eq : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a)) (x:a)
  (y:a), (x = y) -> ((nb_occ x (add x b)) = ((nb_occ x b) + 1%Z)%Z).

Axiom occ_add_neq : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a))
  (x:a) (y:a), (~ (x = y)) -> ((nb_occ y (add x b)) = (nb_occ y b)).

Parameter card: forall {a:Type} {a_WT:WhyType a}, (bag a) -> Z.

Axiom Card_empty : forall {a:Type} {a_WT:WhyType a}, ((card (empty_bag :(bag
  a))) = 0%Z).

Axiom Card_zero_empty : forall {a:Type} {a_WT:WhyType a}, forall (x:(bag a)),
  ((card x) = 0%Z) -> (x = (empty_bag :(bag a))).

Axiom Card_singleton : forall {a:Type} {a_WT:WhyType a}, forall (x:a),
  ((card (singleton x)) = 1%Z).

Axiom Card_union : forall {a:Type} {a_WT:WhyType a}, forall (x:(bag a))
  (y:(bag a)), ((card (union x y)) = ((card x) + (card y))%Z).

Axiom Card_add : forall {a:Type} {a_WT:WhyType a}, forall (x:a) (b:(bag a)),
  ((card (add x b)) = (1%Z + (card b))%Z).

Parameter diff: forall {a:Type} {a_WT:WhyType a}, (bag a) -> (bag a) -> (bag
  a).

Axiom Diff_occ : forall {a:Type} {a_WT:WhyType a}, forall (b1:(bag a))
  (b2:(bag a)) (x:a), ((nb_occ x (diff b1 b2)) = (Zmax 0%Z ((nb_occ x
  b1) - (nb_occ x b2))%Z)).

Axiom Diff_empty_right : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag
  a)), ((diff b (empty_bag :(bag a))) = b).

Axiom Diff_empty_left : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a)),
  ((diff (empty_bag :(bag a)) b) = (empty_bag :(bag a))).

Axiom Diff_add : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a)) (x:a),
  ((diff (add x b) (singleton x)) = b).

Axiom Diff_comm : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a))
  (b1:(bag a)) (b2:(bag a)), ((diff (diff b b1) b2) = (diff (diff b b2) b1)).

Axiom Add_diff : forall {a:Type} {a_WT:WhyType a}, forall (b:(bag a)) (x:a),
  (mem x b) -> ((add x (diff b (singleton x))) = b).

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

Parameter elements: forall {a:Type} {a_WT:WhyType a}, (map.Map.map Z a) -> Z
  -> Z -> (bag a).

Axiom Elements_empty : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z), (j <= i)%Z -> ((elements a1 i
  j) = (empty_bag :(bag a))).

Axiom Elements_add : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z), (i < j)%Z -> ((elements a1 i
  j) = (add (map.Map.get a1 (j - 1%Z)%Z) (elements a1 i (j - 1%Z)%Z))).

Axiom Elements_singleton : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z), (j = (i + 1%Z)%Z) ->
  ((elements a1 i j) = (singleton (map.Map.get a1 i))).

Axiom Elements_union : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z) (k:Z), ((i <= j)%Z /\
  (j <= k)%Z) -> ((elements a1 i k) = (union (elements a1 i j) (elements a1 j
  k))).

Axiom Elements_add1 : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z), (i < j)%Z -> ((elements a1 i
  j) = (add (map.Map.get a1 i) (elements a1 (i + 1%Z)%Z j))).

Axiom Elements_remove_last : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z), (i < (j - 1%Z)%Z)%Z ->
  ((elements a1 i (j - 1%Z)%Z) = (diff (elements a1 i j)
  (singleton (map.Map.get a1 (j - 1%Z)%Z)))).

Axiom Occ_elements : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z) (n:Z), ((i <= j)%Z /\
  (j < n)%Z) -> (0%Z < (nb_occ (map.Map.get a1 j) (elements a1 i n)))%Z.

Axiom Elements_set_outside : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z), (i <= j)%Z -> forall (k:Z),
  ((k < i)%Z \/ (j <= k)%Z) -> forall (e:a), ((elements (map.Map.set a1 k e)
  i j) = (elements a1 i j)).

Axiom Elements_set_inside : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z) (n:Z) (e:a) (b:(bag a)),
  ((i <= j)%Z /\ (j < n)%Z) -> (((elements a1 i n) = (add (map.Map.get a1 j)
  b)) -> ((elements (map.Map.set a1 j e) i n) = (add e b))).

Axiom Elements_set_inside2 : forall {a:Type} {a_WT:WhyType a},
  forall (a1:(map.Map.map Z a)) (i:Z) (j:Z) (n:Z) (e:a), ((i <= j)%Z /\
  (j < n)%Z) -> ((elements (map.Map.set a1 j e) i n) = (add e
  (diff (elements a1 i n) (singleton (map.Map.get a1 j))))).

Parameter min_bag: (bag Z) -> Z.

Axiom Min_bag_singleton : forall (x:Z), ((min_bag (singleton x)) = x).

Axiom Min_bag_union : forall (x:(bag Z)) (y:(bag Z)), ((min_bag (union x
  y)) = (Zmin (min_bag x) (min_bag y))).

Axiom Min_bag_union1 : forall (x:(bag Z)) (y:(bag Z)) (a:Z), (x = (add a
  y)) -> ((min_bag x) = (Zmin a (min_bag y))).

Axiom Min_bag_union2 : forall (x:(bag Z)) (a:Z), (a <= (min_bag x))%Z ->
  (a <= (min_bag (add a x)))%Z.

(* 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 :=
  match v with
  | (mk_ref x) => x
  end.

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

(* Why3 assumption *)
Definition elts {a:Type} {a_WT:WhyType a}(v:(array1 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:(array1 a)): Z :=
  match v with
  | (mk_array x x1) => x
  end.

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

(* Why3 assumption *)
Definition set {a:Type} {a_WT:WhyType a}(a1:(array1 a)) (i:Z) (v:a): (array1
  a) := (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): (array1 a) :=
  (mk_array n (map.Map.const v:(map.Map.map Z a))).

(* Why3 assumption *)
Definition sorted_sub(a:(map.Map.map Z Z)) (l:Z) (u:Z): Prop := forall (i1:Z)
  (i2:Z), (((l <= i1)%Z /\ (i1 <= i2)%Z) /\ (i2 < u)%Z) -> ((map.Map.get a
  i1) <= (map.Map.get a i2))%Z.

(* Why3 assumption *)
Definition sorted_sub1(a:(array1 Z)) (l:Z) (u:Z): Prop :=
  (sorted_sub (elts a) l u).

(* Why3 assumption *)
Definition sorted(a:(array1 Z)): Prop := (sorted_sub (elts a) 0%Z
  (length a)).

Axiom logic_heap : Type.
Parameter logic_heap_WhyType : WhyType logic_heap.
Existing Instance logic_heap_WhyType.

Parameter model: logic_heap -> (bag Z).



(* Why3 goal *)
Theorem Min_of_sorted : forall (a:(map.Map.map Z Z)) (i:Z) (n:Z),
  ((0%Z <= i)%Z /\ (i < n)%Z) -> ((sorted_sub a 0%Z n) ->
  ((min_bag (elements a i n)) = (map.Map.get a i))).
Proof.
intros a i n H_i_n H_sorted.
generalize (H_sorted) (H_i_n).
apply (Z_lt_induction 
  (fun n => sorted_sub a 0 n -> 0 <= i < n -> 
    min_bag (elements a i n) = Map.get a i)%Z); 
  auto with zarith.
intros j H_induc H_sorted_j H_i_j.
assert (h: (i = j-1 \/ i < j-1)%Z) by omega.
   destruct h.
   (* case i = j-1 *)
   subst.
   rewrite Elements_singleton; auto with zarith.
   rewrite Min_bag_singleton; auto.
   (* case i < j-1 *)
   rewrite Elements_add; auto with zarith.
   rewrite Min_bag_union1 with 
      (a := Map.get a (j-1)%Z)
      (y := elements a i (j-1));
     auto.
   assert (h: (Map.get a i <= Map.get a (n-1))%Z).
      apply H_sorted; intuition.
   rewrite Zmin_r; auto.
   rewrite <- (H_induc (j-1)%Z); auto with zarith.
   unfold sorted_sub; auto with zarith.
   pattern (min_bag (elements a i (j-1))); 
     rewrite H_induc; auto with zarith.
   unfold sorted_sub; auto with zarith.
Qed.


