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

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

Axiom iter_def :
  forall {a:Type} {a_WT:WhyType a},
  forall (f:a -> a) (k:Z) (x:a), (0%Z <= k)%Z ->
  ((k = 0%Z) -> ((iter f k x) = x)) /\
  (~ (k = 0%Z) -> ((iter f k x) = (iter f (k - 1%Z)%Z (f x)))).

Axiom iter_1 :
  forall {a:Type} {a_WT:WhyType a},
  forall (f:a -> a) (x:a), ((iter f 1%Z x) = (f x)).

Axiom iter_s :
  forall {a:Type} {a_WT:WhyType a},
  forall (f:a -> a) (k:Z) (x:a), (0%Z < k)%Z ->
  ((iter f k x) = (f (iter f (k - 1%Z)%Z x))).

Axiom t : Type.
Parameter t_WhyType : WhyType t.
Existing Instance t_WhyType.

Parameter eq: t -> t -> Prop.

Axiom eq_spec : forall (x:t) (y:t), (eq x y) <-> (x = y).

Parameter f: t -> t.

Parameter x0: t.

(* Why3 assumption *)
Definition x (i:Z) : t := iter (fun (y0:t) => (f y0)) i x0.

Parameter mu: Z.

Parameter lambda: Z.

Axiom mu_range : (0%Z <= mu)%Z.

Axiom lambda_range : (1%Z <= lambda)%Z.

Axiom distinct :
  forall (i:Z) (j:Z), ((0%Z <= i)%Z /\ (i < (mu + lambda)%Z)%Z) ->
  ((0%Z <= j)%Z /\ (j < (mu + lambda)%Z)%Z) -> ~ (i = j) -> ~ ((x i) = (x j)).

Axiom cycle : forall (n:Z), (mu <= n)%Z -> ((x (n + lambda)%Z) = (x n)).

Axiom cycle_induction :
  forall (n:Z), (mu <= n)%Z -> forall (k:Z), (0%Z <= k)%Z ->
  ((x (n + (lambda * k)%Z)%Z) = (x n)).

(* Why3 assumption *)
Inductive ref (a:Type) :=
  | mk_ref : a -> ref a.
Axiom ref_WhyType : forall (a:Type) {a_WT:WhyType a}, WhyType (ref a).
Existing Instance ref_WhyType.
Arguments mk_ref {a}.

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

(* Why3 assumption *)
Inductive acc {a:Type} {a_WT:WhyType a}: (a -> a -> bool) -> a -> Prop :=
  | acc_x :
      forall (r:a -> a -> bool) (x1:a),
      (forall (y:a), (((r y) x1) = true) -> acc r y) -> acc r x1.

(* Why3 assumption *)
Definition well_founded {a:Type} {a_WT:WhyType a} (r:a -> a -> bool) : Prop :=
  forall (x1:a), acc r x1.

Parameter dist: Z -> Z -> Z.

Axiom dist_def :
  forall (i:Z) (j:Z), (mu <= i)%Z -> (mu <= j)%Z ->
  (0%Z <= (dist i j))%Z /\
  (((x (i + (dist i j))%Z) = (x j)) /\
   forall (k:Z), (0%Z <= k)%Z -> ((x (i + k)%Z) = (x j)) ->
   ((dist i j) <= k)%Z).

(* Why3 assumption *)
Definition rel (t2:t) (t1:t) : Prop :=
  exists i:Z,
  (t1 = (x i)) /\
  ((t2 = (x (i + 1%Z)%Z)) /\
   (((1%Z <= i)%Z /\ (i <= (mu + lambda)%Z)%Z) /\
    ((mu <= i)%Z ->
     ((dist ((2%Z * i)%Z + 2%Z)%Z (i + 1%Z)%Z) < (dist (2%Z * i)%Z i))%Z))).

Parameter rel_closure: t -> t -> bool.

Axiom rel_closure_def :
  forall (y:t) (y1:t), (((rel_closure y) y1) = true) <-> (rel y y1).

Axiom wfrel : well_founded rel_closure.

(* Why3 goal *)
Theorem VC_tortoise_hare :
  forall (hare:t) (tortoise:t),
  (exists t1:Z,
   ((1%Z <= t1)%Z /\ (t1 <= (mu + lambda)%Z)%Z) /\
   ((tortoise = (x t1)) /\
    ((hare = (x (2%Z * t1)%Z)) /\
     forall (i:Z), ((1%Z <= i)%Z /\ (i < t1)%Z) ->
     ~ ((x i) = (x (2%Z * i)%Z))))) ->
  ((eq tortoise hare) <-> (tortoise = hare)) -> ~ (eq tortoise hare) ->
  forall (tortoise1:t), (tortoise1 = (f tortoise)) -> forall (hare1:t),
  (hare1 = (f (f hare))) ->
  (rel tortoise1 tortoise) /\ (acc rel_closure tortoise).
(* Why3 intros hare tortoise (t1,((h1,h2),(h3,(h4,h5)))) h6 h7 tortoise1 h8
        hare1 h9. *)
Proof.
intros hare tortoise (i,((h1,h2),(h3,(h4,h5)))) h6 h7 tortoise1 h8 hare1 h9.
split. 2: apply wfrel.
exists i; intuition.
subst.
unfold x.
rewrite iter_s with (k := (i+1)%Z).
ring_simplify (i+1-1)%Z; auto.
omega.
assert (mu1: (mu <= 2*i+2)%Z) by omega.
assert (mu2: (mu <= i+1)%Z) by omega.
generalize (dist_def (2*i+2) (i+1) mu1 mu2)%Z.
intros (d1, (d2, d3)).
clear mu1 mu2.
assert (mu1: (mu <= 2*i)%Z) by omega.
generalize (dist_def (2*i) i mu1 H1)%Z.
intros (d'1, (d'2, d'3)).
apply Zle_lt_trans with (dist (2 * i) i - 1)%Z.
apply d3.
assert (case: (dist (2*i) i = 0 \/ dist (2*i) i > 0)%Z) by omega. destruct case.
rewrite H2 in d'2.
subst.
absurd (iter f i x0 = iter f (2 * i) x0)%Z; auto.
symmetry.
ring_simplify (2*i+0)%Z in d'2.
auto.
omega.
unfold x.
rewrite iter_s; try omega.
rewrite iter_s with (k:=(i+1)%Z); try omega.
apply f_equal.
ring_simplify (i+1-1)%Z.
ring_simplify (2 * i + 2 + (dist (2 * i) i - 1) - 1)%Z.
auto.
omega.
Qed.

