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

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

Parameter t : Type.

Parameter f: t -> t.

Parameter x0: t.

Parameter iter: Z -> t -> t.

Axiom iter_0 : forall (x:t), ((iter 0%Z x) = x).

Axiom iter_s : forall (k:Z) (x:t), (0%Z < k)%Z -> ((iter k
  x) = (iter (k - 1%Z)%Z (f x))).

Axiom iter_1 : forall (x:t), ((iter 1%Z x) = (f x)).

Axiom iter_s2 : forall (k:Z) (x:t), (0%Z < k)%Z -> ((iter k
  x) = (f (iter (k - 1%Z)%Z x))).

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)) -> ~ ((iter i x0) = (iter j x0)))).

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

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

(* Why3 assumption *)
Inductive ref (a:Type) :=
  | mk_ref : a -> ref a.
Implicit Arguments mk_ref.

(* Why3 assumption *)
Definition contents (a:Type)(v:(ref a)): a :=
  match v with
  | (mk_ref x) => x
  end.
Implicit Arguments contents.

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 /\ (((iter (i + (dist i j))%Z x0) = (iter j x0)) /\
  forall (k:Z), (0%Z <= k)%Z -> (((iter (i + k)%Z x0) = (iter j x0)) ->
  ((dist i j) <= k)%Z)))).

(* Why3 assumption *)
Definition rel(t2:t) (t1:t): Prop := exists i:Z, (t1 = (iter i x0)) /\
  ((t2 = (iter (i + 1%Z)%Z x0)) /\ (((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))).


(* Why3 goal *)
Theorem WP_parameter_tortoise_hare : forall (hare:t) (tortoise:t),
  (exists t1:Z, ((1%Z <= t1)%Z /\ (t1 <= (mu + lambda)%Z)%Z) /\
  ((tortoise = (iter t1 x0)) /\ ((hare = (iter (2%Z * t1)%Z x0)) /\
  forall (i:Z), ((1%Z <= i)%Z /\ (i < t1)%Z) -> ~ ((iter i
  x0) = (iter (2%Z * i)%Z x0))))) -> ((~ (tortoise = hare)) ->
  forall (tortoise1:t), (tortoise1 = (f tortoise)) -> forall (hare1:t),
  (hare1 = (f (f hare))) -> (rel tortoise1 tortoise)).
(* YOU MAY EDIT THE PROOF BELOW *)
intuition.
clear H2.
destruct H as (i, (h1, (h2, (h3, h4)))).
red.
exists i; intuition.
subst.
rewrite iter_s2 with (k := (i+1)%Z).
apply f_equal.
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 H3)%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 H4 in d'2.
subst.
absurd (iter i x0 = iter (2 * i) x0)%Z; auto.
symmetry.
ring_simplify (2*i+0)%Z in d'2.
auto.
omega.
rewrite iter_s2; try omega.
rewrite iter_s2 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.


