(* This file is generated by Why3's Coq driver *)
(* Beware! Only edit allowed sections below    *)
Require Import BuiltIn.
Require BuiltIn.
Require int.Int.
Require list.List.
Require list.Length.
Require list.Mem.
Require list.Append.
Require list.Reverse.

(* Why3 assumption *)
Inductive tree :=
  | Leaf : tree
  | Node : tree -> tree -> tree.
Axiom tree_WhyType : WhyType tree.
Existing Instance tree_WhyType.

(* Why3 assumption *)
Fixpoint depths (d:Numbers.BinNums.Z)
  (t:tree) {struct t}: Init.Datatypes.list Numbers.BinNums.Z :=
  match t with
  | Leaf => Init.Datatypes.cons d Init.Datatypes.nil
  | Node l r =>
      Init.Datatypes.app (depths (d + 1%Z)%Z l) (depths (d + 1%Z)%Z r)
  end.

Axiom depths_head :
  forall (t:tree) (d:Numbers.BinNums.Z),
  match depths d t with
  | Init.Datatypes.cons x _ => (d <= x)%Z
  | Init.Datatypes.nil => False
  end.

Axiom depths_unique :
  forall (t1:tree) (t2:tree) (d:Numbers.BinNums.Z)
    (s1:Init.Datatypes.list Numbers.BinNums.Z)
    (s2:Init.Datatypes.list Numbers.BinNums.Z),
  ((Init.Datatypes.app (depths d t1) s1) =
   (Init.Datatypes.app (depths d t2) s2)) ->
  (t1 = t2) /\ (s1 = s2).

Axiom depths_prefix :
  forall (t:tree) (d1:Numbers.BinNums.Z) (d2:Numbers.BinNums.Z)
    (s1:Init.Datatypes.list Numbers.BinNums.Z)
    (s2:Init.Datatypes.list Numbers.BinNums.Z),
  ((Init.Datatypes.app (depths d1 t) s1) =
   (Init.Datatypes.app (depths d2 t) s2)) ->
  (d1 = d2).

Axiom depths_prefix_simple :
  forall (t:tree) (d1:Numbers.BinNums.Z) (d2:Numbers.BinNums.Z),
  ((depths d1 t) = (depths d2 t)) -> (d1 = d2).

Axiom depths_subtree :
  forall (t1:tree) (t2:tree) (d1:Numbers.BinNums.Z) (d2:Numbers.BinNums.Z)
    (s1:Init.Datatypes.list Numbers.BinNums.Z),
  ((Init.Datatypes.app (depths d1 t1) s1) = (depths d2 t2)) -> (d2 <= d1)%Z.

Axiom depths_unique2 :
  forall (t1:tree) (t2:tree) (d1:Numbers.BinNums.Z) (d2:Numbers.BinNums.Z),
  ((depths d1 t1) = (depths d2 t2)) -> (d1 = d2) /\ (t1 = t2).

(* Why3 assumption *)
Fixpoint forest_depths
  (f:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type) {struct f}: 
  Init.Datatypes.list Numbers.BinNums.Z :=
  match f with
  | Init.Datatypes.nil => Init.Datatypes.nil
  | Init.Datatypes.cons (d, t) r =>
      Init.Datatypes.app (depths d t) (forest_depths r)
  end.

Axiom forest_depths_append :
  forall (f1:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type)
    (f2:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type),
  ((forest_depths (Init.Datatypes.app f1 f2)) =
   (Init.Datatypes.app (forest_depths f1) (forest_depths f2))).

(* Why3 assumption *)
Fixpoint greedy (d:Numbers.BinNums.Z) (d1:Numbers.BinNums.Z)
  (t1:tree) {struct t1}: Prop :=
  ~ (d = d1) /\
  match t1 with
  | Leaf => True
  | Node l1 _ => greedy d (d1 + 1%Z)%Z l1
  end.

(* Why3 assumption *)
Inductive g: Init.Datatypes.list (Numbers.BinNums.Z* tree)%type -> Prop :=
  | Gnil : g Init.Datatypes.nil
  | Gone :
      forall (d:Numbers.BinNums.Z) (t:tree),
      g (Init.Datatypes.cons (d, t) Init.Datatypes.nil)
  | Gtwo :
      forall (d1:Numbers.BinNums.Z) (d2:Numbers.BinNums.Z) (t1:tree)
        (t2:tree) (l:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type),
      greedy d1 d2 t2 -> g (Init.Datatypes.cons (d1, t1) l) ->
      g (Init.Datatypes.cons (d2, t2) (Init.Datatypes.cons (d1, t1) l)).

Axiom g_append :
  forall (l1:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type)
    (l2:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type),
  g (Init.Datatypes.app l1 l2) -> g l1.

Axiom depths_length :
  forall (t:tree) (d:Numbers.BinNums.Z),
  (1%Z <= (list.Length.length (depths d t)))%Z.

Axiom forest_depths_length :
  forall (l:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type),
  (0%Z <= (list.Length.length (forest_depths l)))%Z.

Axiom g_tail :
  forall (l1:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type)
    (l2:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type),
  g (Init.Datatypes.app l1 l2) -> g l2.

Axiom key_lemma :
  forall (t:tree) (l:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type)
    (d:Numbers.BinNums.Z) (d1:Numbers.BinNums.Z) (t1:tree)
    (s:Init.Datatypes.list Numbers.BinNums.Z),
  (d < d1)%Z -> (1%Z <= (list.Length.length l))%Z ->
  g (Lists.List.rev (Init.Datatypes.cons (d1, t1) l)) ->
  ~ ((forest_depths (Init.Datatypes.cons (d1, t1) l)) =
     (Init.Datatypes.app (depths d t) s)).


Require Import Lia.

(* Why3 goal *)
Theorem right_nil :
  forall (l:Init.Datatypes.list (Numbers.BinNums.Z* tree)%type),
  (2%Z <= (list.Length.length l))%Z -> g l ->
  forall (t:tree) (d:Numbers.BinNums.Z),
  ~ ((forest_depths (Lists.List.rev l)) = (depths d t)).
(* Why3 intros l h1 h2 t d. *)
intros l H hg.
replace l with (List.rev (List.rev l)) in H, hg. 2:apply Reverse.reverse_reverse.
generalize H; clear H. generalize hg; clear hg.
generalize (List.rev l). clear l.

destruct l.
(* l = Nil => contradiction *)
intros.
simpl in H. lia.
(* l = Cons *)
intros. destruct p as (d1, t1).
intros eq.
assert (d < d1)%Z.
  simpl in eq.
  assert (d <= d1)%Z. apply (depths_subtree _ _ _ _ _ eq).
  assert (d <> d1)%Z. intro.
  subst.
  assert (depths d1 t = app (depths d1 t) nil). auto with *.
  assert (t = t1). rewrite H1 in eq. generalize (depths_unique _ _ _ _ _ eq).
   intuition.
  subst.
  assert (forest_depths l = nil). rewrite H1 in eq at 2.
    generalize (depths_unique _ _ _ _ _ eq). intuition.
  simpl in H.
  destruct l. simpl in H. lia.
  assert (cons p l = nil).
  destruct (cons p l); auto.
  simpl in H2. destruct p0. 
    generalize (depths_head t z). destruct (depths z t). intuition.
    simpl in H2. discriminate H2.
  discriminate H3.
  lia.
generalize eq; clear eq.
replace (depths d t) with (app (depths d t) nil).
   2:rewrite Append.Append_l_nil; trivial.
apply key_lemma; auto.
simpl in H. 
rewrite Append.Append_length in H.
rewrite Reverse.Reverse_length in H. simpl in H.
lia.
Qed.

