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

(* 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 color :=
  | Blue : color
  | White : color
  | Red : color.
Axiom color_WhyType : WhyType color.
Existing Instance color_WhyType.

(* Why3 assumption *)
Definition monochrome (a:(@map.Map.map Z _ color color_WhyType)) (i:Z) (j:Z)
  (c:color): Prop := forall (k:Z), ((i <= k)%Z /\ (k < j)%Z) ->
  ((map.Map.get a k) = c).

Parameter nb_occ: (@map.Map.map Z _ color color_WhyType) -> Z -> Z -> color
  -> Z.

Axiom nb_occ_null : forall (a:(@map.Map.map Z _ color color_WhyType)) (i:Z)
  (j:Z) (c:color), (j <= i)%Z -> ((nb_occ a i j c) = 0%Z).

Axiom nb_occ_add_eq : forall (a:(@map.Map.map Z _ color color_WhyType)) (i:Z)
  (j:Z) (c:color), ((i < j)%Z /\ ((map.Map.get a (j - 1%Z)%Z) = c)) ->
  ((nb_occ a i j c) = ((nb_occ a i (j - 1%Z)%Z c) + 1%Z)%Z).

Axiom nb_occ_add_neq : forall (a:(@map.Map.map Z _ color color_WhyType))
  (i:Z) (j:Z) (c:color), ((i < j)%Z /\ ~ ((map.Map.get a
  (j - 1%Z)%Z) = c)) -> ((nb_occ a i j c) = (nb_occ a i (j - 1%Z)%Z c)).

Axiom nb_occ_split : forall (a:(@map.Map.map Z _ color color_WhyType)) (i:Z)
  (j:Z) (k:Z) (c:color), ((i <= j)%Z /\ (j <= k)%Z) -> ((nb_occ a i k
  c) = ((nb_occ a i j c) + (nb_occ a j k c))%Z).

Open Scope Z_scope.

(* Why3 goal *)
Theorem nb_occ_ext : forall (a1:(@map.Map.map Z _ color color_WhyType))
  (a2:(@map.Map.map Z _ color color_WhyType)) (i:Z) (j:Z) (c:color),
  (forall (k:Z), ((i <= k)%Z /\ (k < j)%Z) -> ((map.Map.get a1
  k) = (map.Map.get a2 k))) -> ((nb_occ a1 i j c) = (nb_occ a2 i j c)).
intros a1 a2 i j c.
assert (i < j \/ j <= i) by omega.
destruct H. 

pattern j; apply Zlt_lower_bound_ind with (z:=i); intuition.

assert (i = x \/ i < x) by omega; destruct H3.
rewrite (nb_occ_null a2) by auto with zarith;
apply nb_occ_null; auto with zarith.

assert (nb_occ a1 i (x - 1) c = nb_occ a2 i (x - 1) c).
apply H0; auto with zarith.

generalize (why_decidable_eq (map.Map.get a1 (x - 1)) c);
intros [h1|h1].

rewrite (nb_occ_add_eq a1) by auto;
rewrite (nb_occ_add_eq a2).
rewrite H4; auto.
rewrite <- H2; auto with zarith.

rewrite (nb_occ_add_neq a1) by auto; rewrite (nb_occ_add_neq a2).
auto.
rewrite <- H2; auto with zarith.

intros.
rewrite nb_occ_null by auto with zarith.
rewrite nb_occ_null by auto with zarith.
auto.
Qed.


