(* ============================================================ *)
(* First part *)

(* Binary trees *)

Section sbt.
Variable A: Set.

Inductive bintree : Set :=
  | L: bintree  (* leaf *)
  | N: bintree -> A -> bintree -> bintree.
       (* node with left subtree, value, right subtree *)

Fixpoint size (t: bintree) : nat := 
  match t with
  | L => 0
  | N l x r => size l + (1 + size r)
  end.

Fixpoint nb_leaves (t: bintree) : nat := 
  match t with
  | L => 1
  | N l x r => nb_leaves l + nb_leaves r
  end.

Lemma size_nb_leaves : forall t, nb_leaves t = 1 + size t.
Proof.
Admitted.

Definition admit {T: Type} : T.  Admitted.

Fixpoint list_of_values (t: bintree) : list A := admit.

Lemma size_length : forall t, length (list_of_values t) = size t.
Admitted.

End sbt.


(* ============================================================ *)
(* Second part *)

(* Induction on an inductively defined predicate *)

(* Computational definition of even *)
Fixpoint evenb (n: nat) : bool :=
  match n with
  | 0 => true
  | 1 => false
  | S (S n) => evenb n
  end.

(* Inductive definition of even *)
Inductive even : nat -> Prop :=
  | E0 : even 0
  | E2 : forall n, even n -> even (S (S n)).

(* Now we show that these two definitions are equivalent *)

(* First direction *)
Lemma evenb_even : forall n, evenb n = true -> even n.
Proof. 
induction n as [ | n Hn].
  intros e. apply E0. 
  (* Here we are stuck; do you see why? *)
Abort.

(* To solve it we prove a stronger property by induction:
   the expected property holds simultaneously on [n] and [S n] *)
Lemma stronger_evenb_even : 
  forall n, (evenb n = true -> even n) /\ (evenb (S n) = true -> even (S n)).
Proof.
Admitted.

Lemma evenb_even : forall n, evenb n = true -> even n.
Proof.
Admitted.

(* Another interesting technique is to program the proof following
   the very shape of evenb *)
(* The tactic [refine] takes a partial proof as an argument,
   that is, a proof term with "holes" represented by [_], 
   to be filled later -- correponding subgoals will show up  *)
Fixpoint other_evenb_even (n: nat) : evenb n = true -> even n.
Proof.
refine (match n with
  | 0 => _ (* yields subgoal 1 *)
  | 1 => _  (* yields subgoal 2 *)
  | S (S n') => _  (* yields subgoal 3 *)
  end); simpl; intro e. 
Admitted.


(* Second direction *)
Lemma even_evenb : forall n, even n -> evenb n = true.
Proof.
(* Let us try again by induction on n *)
intro n. induction n.
   simpl. reflexivity. 
   (* Similar problem as in the first attempt for [evenb_even] *)
Restart.
(* It is possible to solve it similarly, by strenghtening or Fixpoint *)
(* Please try. *)
(* One of the subgoals requires a special technique
   to be introduced in the next lecture, called inversion :
   even 1 -> something
   In some sense this subgoal is stupid because it should not even
   be considered. *)
(* MUCH BETTER: using induction on [e: even n] actually avoids this stupid
   subgoal *)
intros n e. induction e as [ | n e He].
Admitted.

(* Other examples *)
Lemma even_plus: forall n m, even n -> even m -> even (n+m). 
Proof.
Admitted.

Check plus_n_Sm.
Lemma even_half: forall n, even n -> exists h, n = h + h.
Proof.
Admitted.

(* Another inductive definition: less_or_equal *)
(* In the stadard library, we use the notation n <= m for [le n m] *)
Print le.
(*
Inductive le (n : nat) : nat -> Prop :=
  | le_n : n <= n
  | le_S : forall m : nat, n <= m -> n <= S m.
*)

Lemma le_plus: forall n m, n <= m -> S n <= S m.
Admitted.

Lemma le_delta: forall n m, n <= m -> exists x, (x + n = m).
Admitted.


