(* 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.

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.


(* Why3 goal *)
Theorem 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)).
Proof.
intros X _X a i.
apply 
 (Zlt_lower_bound_rec (fun j => forall k : Z,
   k < i \/ j <= k -> forall e : X, 
    elements (Map.set a k e) i j = elements a i j) i)%Z.
intros j H_induc H_j k H_k e.
assert (h: (i=j \/ i<j)%Z) by omega.
destruct h.
 (* case i=j *)
 subst.
 do 2 (rewrite Elements_empty; auto).
 (*case i < j*)
 generalize (H_induc (j-1))%Z.
 clear H_induc; intro H_induc.
 rewrite Elements_add; auto with *.
 pattern (elements a i j); rewrite Elements_add; auto with *.
 rewrite Map.Select_neq; auto with zarith.
 apply f_equal2; auto.
 apply H_induc;intuition.
Qed.


