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

Axiom bag : forall (a:Type), 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 -> Numbers.BinNums.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_right :
  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 y (add x b)) = ((nb_occ y 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 -> Numbers.BinNums.Z.

Axiom Card_nonneg :
  forall {a:Type} {a_WT:WhyType a}, forall (x:bag a), (0%Z <= (card x))%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)) =
   (ZArith.BinInt.Z.max 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).

Parameter choose: forall {a:Type} {a_WT:WhyType a}, bag a -> a.

Axiom choose_mem :
  forall {a:Type} {a_WT:WhyType a},
  forall (b:bag a), ~ ((empty_bag : bag a) = b) -> mem (choose b) b.

(* Why3 assumption *)
Definition array (a:Type) := Numbers.BinNums.Z -> a.

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

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

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

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

Axiom Elements_union :
  forall {a:Type} {a_WT:WhyType a},
  forall (a1:Numbers.BinNums.Z -> a) (i:Numbers.BinNums.Z)
    (j:Numbers.BinNums.Z) (k:Numbers.BinNums.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:Numbers.BinNums.Z -> a) (i:Numbers.BinNums.Z)
    (j:Numbers.BinNums.Z),
  (i < j)%Z -> ((elements a1 i j) = (add (a1 i) (elements a1 (i + 1%Z)%Z j))).

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

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

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

(* Why3 goal *)
Theorem Elements_set_inside {a:Type} {a_WT:WhyType a} :
  forall (a1:Numbers.BinNums.Z -> a) (i:Numbers.BinNums.Z)
    (j:Numbers.BinNums.Z) (n:Numbers.BinNums.Z) (e:a) (b:bag a),
  (i <= j)%Z /\ (j < n)%Z -> ((elements a1 i n) = (add (a1 j) b)) ->
  ((elements (map.Map.set a1 j e) i n) = (add e b)).
(* Why3 intros a1 i j n e b (h1,h2) h3. *)
Proof.
rename a into X.
intros a i j n e b Hi H.
apply bag_simpl_left with (a1:=(add (a j) empty_bag)).
replace (add e b) with (union b (add e empty_bag)).
2: rewrite Union_comm ; unfold add ; rewrite Union_identity; auto.
rewrite Union_assoc.
unfold add; rewrite Union_identity.
unfold add in H; rewrite <- H; clear H.
rewrite (Elements_union _ _ j); auto with zarith.
rewrite elements_set_outside; auto with zarith.
pattern (elements (Map.set a j e) j n); rewrite Elements_add1; auto with zarith.
rewrite elements_set_outside; auto with zarith.
rewrite (Elements_union _ i j n); auto with zarith.
rewrite (proj1 (Map.set'def _ _ _ _)); auto with zarith.
pattern (elements a j n); rewrite Elements_add1; auto with zarith.
(* AC1 equality *)
rewrite Union_identity.
rewrite Union_assoc.
pattern (union (singleton (a j)) (elements a i j)); rewrite Union_comm.
rewrite <- Union_assoc.
rewrite <- Union_assoc.
apply f_equal.
unfold add.
rewrite <- Union_assoc.
apply f_equal.
apply Union_comm.
Qed.

