Require Import Arith.

(* We first want to prove that our definition of add satisfies commutativity. *)

Fixpoint add n m :=
  match n with 0 => m | S p => add p (S m) end.

Lemma addnS : forall n m, add n (S m) = S (add n m).
Proof.
 induction n.
 intros m; simpl.
 reflexivity.
 intros m; simpl.
 apply IHn.
Qed.

(* Q1. Prove the following two theorems: beware that you will probably need
  addnS. *)
Lemma addn0 : forall n, add n 0 = n.
Proof.
 induction n;simpl;auto.
 rewrite addnS.
 rewrite IHn;trivial.
Qed.

Lemma add_comm : forall n m, add n m = add m n.
Proof.
 induction n;simpl.
 intro;rewrite addn0;auto.
 intros;rewrite addnS.
 rewrite IHn;trivial.
 rewrite addnS.
 trivial.
Qed.

(* Q2. Now state and prove the associativity of this function. *)

Lemma plus_assoc : forall n m p, add n (add m p)= add (add n m) p.
Proof.
 induction n.
 simpl;auto.
 intros.
 simpl.
 repeat rewrite <- addnS.
 rewrite IHn.
 repeat rewrite addnS.
 simpl.
 rewrite addnS.
 trivial.
Qed.

(* Q3. Now state and prove a theorem that expresses that this add function
  returns the same result as plain addition (given by function plus) *)

Lemma add_plus : forall n p, add n p = n+p.
Proof.
  induction n; simpl; auto.
  intro; rewrite addnS.
  rewrite IHn;trivial.
Qed.

(* Note that the theorems about commutativity and associativity could be
  consequences of add_plus. *)

(* Programs about lists.  *)
Require Import List ZArith.

(* We re-use the permutation defined in course C2. *)

Fixpoint multiplicity (n:Z)(l:list Z) : nat :=
  match l with
    nil => 0%nat
  | a::l' => if Zeq_bool n a then S (multiplicity n l') else multiplicity n l'
  end.

Definition is_perm (l l':list Z) :=
  forall n, multiplicity n l = multiplicity n l'.

(* Q4. Show the following theorem: *)

Lemma multiplicity_app : forall x l1 l2, multiplicity x (l1++l2) =
    multiplicity x l1 + multiplicity x l2.
Proof.
 induction l1;simpl;auto.
 case (Zeq_bool x a).
 intros;rewrite IHl1.
 simpl;auto.
 intros;rewrite IHl1.
 simpl;auto.
Qed.

(* Q5. State and prove a theorem that expresses that element counts are
  preserved by reverse. *)
Require Import ArithRing.

Lemma multiplicity_rev : forall x l, multiplicity x (rev l) = multiplicity x l.
Proof.
 induction l;simpl;auto.
 rewrite multiplicity_app.
 simpl.
 case (Zeq_bool x a).
 rewrite IHl;auto with arith.
 ring.
 rewrite IHl;ring.
Qed.

(* --------------------------------------------*)
(* The following questions are more advanced and can be kept for later. *)

(* Q6. Show the following theorem.  You will probably have an occasion
  to use the ring tactic *)

Lemma is_perm_transpose :
  forall x y l1 l2 l3, is_perm (l1++x::l2++y::l3) (l1++y::l2++x::l3).
Proof.
 intros;unfold is_perm;intros.
 replace (l1 ++ x :: l2 ++ y :: l3) with (l1 ++ (x::nil) ++ l2 ++ (y::nil)++l3).
 2:simpl;auto.
 replace (l1 ++ y:: l2 ++ x :: l3) with (l1 ++ (y::nil) ++ l2 ++ (x::nil)++l3).
 2:simpl;auto.
 repeat rewrite multiplicity_app.
 ring.
Qed.

(* Q5 : What does this function do? *)
Fixpoint mask (A : Type)(m : list bool)(s : list A) {struct m} :=
  match m, s with
  | b :: m', x :: s' => if b then x :: mask A m' s' else mask A m' s'
  | _, _ => nil
  end.

Implicit Arguments mask.

(* Q6 Prove that : *)
Lemma mask_cat A m1 (s1 : list A) :
    length m1 = length s1 ->
  forall m2 s2, mask (m1 ++ m2) (s1 ++ s2) = mask m1 s1 ++ mask m2 s2.
Proof.
intros Hm1 m2 s2.
revert s1 Hm1.
induction m1 as [|b1 m1 IHm]; intros [|x1 s1]; trivial.
  now intros H; inversion H.
  now intros H; inversion H.
intros Hm1; injection Hm1; intros Hm1'; simpl.
now rewrite (IHm _ Hm1'); case b1.
Qed.


Require Import List.
Require Import Relations.
Require Import list.

(* inductive predicate expressing the fact that two lists are obtained from
each other, by the permutation of two consecutive elements  *)
Inductive Transpose {A:Type} : list A -> list A -> Prop :=
  | transp_refl :   forall (l: list A), Transpose l l
  | transp_pair :   forall(x y:A), Transpose (x::y::nil) (y::x::nil)
  | transp_gen  :   forall (l m l1 l2 : list A),
    Transpose l m -> Transpose (l1++l++l2) (l1++m++l2).

(* one common issue with this sort of definition is that constructors of the
inductive predicates are akin to 'axioms', and it is very easy to define the
wrong thing, or things that are inconsistent, or incomplete etc *)

(* Here is another way to go about it *)
Definition Transpose' {A:Type} (l: list A) (m:list A) : Prop :=
  l = m \/ (exists (l1 l2:list A) (x y:A),
  l = l1++(x::y::nil)++l2 /\ m = l1++(y::x::nil)++l2).

(* Transpose' is a reflexive relation on list A *)
Lemma Transpose_refl': forall (A:Type), reflexive (list A) Transpose'.
Proof.
  intros A. unfold reflexive. intros l. unfold Transpose'. left. reflexivity.
Qed.

(* ideally, you want to check the equivalence between Transpose and Transpose' *)
Lemma Transpose_check: forall (A:Type),
  same_relation (list A) Transpose Transpose'.
Proof.
  intros A. unfold same_relation. split.
  unfold inclusion.
  intros l m. intro H. generalize H. elim H.
    clear H l m. intros l H. clear H. apply Transpose_refl'.
    clear H l m. intros x y H. clear H. unfold Transpose'. right.
      exists nil, nil, x, y. split; reflexivity.
    clear H l m. intros l m l1 l2 H0 H1 H2. clear H2.
      cut (Transpose' l m). clear H0 H1. intro H.
      unfold Transpose' in H. elim H.
        clear H. intro H. rewrite H. apply Transpose_refl'.
        clear H. intro H. elim H.
        clear H. intros l3 H. elim H.
        clear H. intros l4 H. elim H.
        clear H. intros x H. elim H.
        clear H. intros y H. unfold Transpose'. right.
          exists (l1++l3), (l4++l2), x, y. elim H.
            clear H. intros H0 H1. split.
            rewrite H0. set (k:= x::y::nil).
            rewrite <- app_assoc, <- app_assoc, <- app_assoc. reflexivity.
            rewrite H1. set (k:= y::x::nil).
            rewrite <- app_assoc, <- app_assoc, <- app_assoc. reflexivity.
            apply H1. exact H0.
  unfold inclusion.
  intros l m H. unfold Transpose' in H. elim H.
    clear H. intro H. rewrite H. apply transp_refl.
    clear H. intro H. elim H.
      clear H. intros l1 H. elim H.
      clear H. intros l2 H. elim H.
      clear H. intros x H. elim H.
      clear H. intros y H. elim H.
      clear H. intros Hl Hm. rewrite Hl, Hm.
      apply transp_gen. apply transp_pair.
Qed.

(* This version of the lemma can be handy for rewrites *)
Lemma Transpose_check': forall (A:Type) (l m: list A),
  Transpose l m <-> Transpose' l m.
Proof.
  intros A l m. split.
    intro H. apply Transpose_check. exact H.
    intro H. apply Transpose_check. exact H.
Qed.

(* Transpose is a reflexive relation on list A *)
Lemma Transpose_refl: forall (A:Type), reflexive (list A) Transpose.
Proof.
   intros A. unfold reflexive. intros l. apply transp_refl.
Qed.

(* Transpose is a symmetric relation on list A *)
Lemma Transpose_sym: forall (A:Type), symmetric (list A) Transpose.
Proof.
  intros A. unfold symmetric. intros l m H. generalize H. elim H.
    clear H l m. intros. apply transp_refl.
    clear H l m. intros. apply transp_pair.
    clear H l m. intros l m l1 l2 H0 H1 H2. clear H2.
      apply transp_gen. apply H1. exact H0.
Qed.

(* Two lists which are transpositions of one another have same length *)
Lemma Transpose_imp_eq_length: forall (A:Type)(l m:list A),
  Transpose l m -> length l = length m.
Proof.
  intros A l m H. generalize H. elim H.
    clear H l m. intros. simpl. reflexivity.
    clear H l m. intros. simpl. reflexivity.
    clear H l m. intros l m l1 l2 H0 H1 H2. clear H2.
  rewrite app_length, app_length, app_length, app_length.
  rewrite H1. reflexivity. exact H0.
Qed.

Lemma Transpose_l_nil: forall (A:Type)(l:list A),
  Transpose l nil -> l = nil.
Proof.
  intros A l H. apply length_zero_iff_nil.
  apply Transpose_imp_eq_length with (m:=nil). exact H.
Qed.

Lemma Transpose_cons: forall (A:Type)(l m:list A)(a: A),
  Transpose l m -> Transpose (a::l) (a::m).
Proof.
 intros A l m a H.
 cut (a::l = (a::nil) ++ l ++ nil).
 cut (a::m = (a::nil) ++ m ++ nil).
 intros Hm Hl. rewrite Hm, Hl. apply transp_gen. exact H.
 rewrite <- app_comm_cons. rewrite app_nil_l. rewrite app_nil_r. reflexivity.
 rewrite <- app_comm_cons. rewrite app_nil_l. rewrite app_nil_r. reflexivity.
Qed.

Lemma Transpose_cons_reverse: forall (A:Type)(l m:list A)(a:A),
  Transpose (a::l) (a::m) -> Transpose l m.
Proof.
  intros A l m a.
  cut (forall (l' m':list A),
    l' = a::l -> m' = a::m -> Transpose l' m' -> Transpose l m). eauto.
  intros l' m' Hl Hm H. generalize H Hl Hm.
  clear Hl Hm. generalize l m a. clear l m a. elim H.
    clear H l' m'. intros k l m a H0 H1 H2. clear H0.
      rewrite H1 in H2. clear H1. injection H2. intros H0.
      rewrite H0. apply Transpose_refl.
    clear H l' m'. intros x y l m a H0 H1 H2. clear H0.
      injection H1. clear H1. injection H2. clear H2.
      intros H0 H1 H2 H3.
      rewrite H3 in H0. clear H3. rewrite H1 in H2. clear H1.
      rewrite H2 in H0. clear H2. rewrite H0. apply Transpose_refl.
    clear H l' m'. intros l m l1 l2 H0 H1 l' m' a H2 H3 H4.
      generalize (destruct_list l1). intro H5. elim H5.
        clear H5. intro H5. elim H5. clear H5. intros x H5. elim H5.
          clear H5. intros k1 H5. rewrite H5 in H3. rewrite H5 in H4.
          rewrite <- app_comm_cons in H3. rewrite <- app_comm_cons in H4.
          injection H3. injection H4. clear H3 H4 H5. intros H3 H4. clear H4.
          intros H4 H5. clear H5. rewrite <- H3, <- H4. clear H3 H4.
          apply transp_gen. exact H0.
        clear H5. intro H5. rewrite H5 in H3. rewrite H5 in H4.
          rewrite app_nil_l in H3. rewrite app_nil_l in H4. clear H2 H5.
          generalize (destruct_list l). generalize (destruct_list m).
          intros H5 H6. elim H5.
            clear H5. intro H5. elim H5. clear H5. intros b H5. elim H5.
              clear H5. clear l1. intros l1 H5. rewrite H5 in H4.
              rewrite <- app_comm_cons in H4. injection H4. clear H4.
              intro H4. intro H7. rewrite H7 in H5. clear H7 b. elim H6.
                clear H6. intro H6. elim H6. clear H6. intros b H6. elim H6.
                  clear H6. intros k1 H6. rewrite H6 in H3.
                  rewrite <- app_comm_cons in H3. injection H3. clear H3.
                  intro H3. intro H7. rewrite H7 in H6. clear H7 b.
                  rewrite <- app_nil_l with (l:=k1++l2) in H3. rewrite <- H3.
                  rewrite <- app_nil_l with (l:=l1++l2) in H4. rewrite <- H4.
                  apply transp_gen. apply H1 with (a:=a). exact H0.
                  exact H6. exact H5.
                clear H6. intro H6. rewrite H6 in H0. apply Transpose_sym in H0.
                  apply Transpose_l_nil in H0. rewrite H0 in H5. discriminate H5.
            clear H5. intro H5. rewrite H5 in H0. apply Transpose_l_nil in H0.
              rewrite H0 in H3. rewrite app_nil_l in H3.
              rewrite H5 in H4. rewrite app_nil_l in H4. rewrite H3 in H4.
              injection H4. clear H4. intro H4. rewrite H4. apply Transpose_refl.
Qed.

(* This inductive predicate expresses the fact that two
lists are permutation of one another *)
Inductive Permute {A:Type} : list A -> list A -> Prop :=
  | perm_refl : forall l:list A, Permute l l
  | perm_next : forall l l' m: list A,
    Permute l l' -> Transpose l' m -> Permute l m.

(* Permute is a reflexive relation on list A *)
Lemma Permute_refl : forall (A:Type), reflexive (list A) Permute.
Proof.
  intros A. unfold reflexive. intros l. apply perm_refl.
Qed.

(* As defined, the Permute relation is such that if l1 is
  a permutation of l2 and l2 is a transposition of l3, then
  l1 is deemed a permutation of l3. In order to prove that
  the Permute relation is symmetric, we need to be able to
  argue the other way around, namely that if l1 is a
  transposition of l2 and l2 is a permutation of l3, then
  l1 is also a permutation of l3. This result is obvious
  once we have established the symmetry of both Transpose
  and Permute, but we are not there yet. *)
Lemma Transpose_first: forall (A:Type) (l l' m:list A),
  Transpose l l' -> Permute l' m -> Permute l m.
Proof.
  intros A l l' m H0 H1. generalize H0. clear H0. generalize H1 l.
  elim H1. clear H1 l l' m. intros m. intro H. clear H. intro l.
  intro H. apply perm_next with (l':=l). apply perm_refl. exact H.
  clear H1 l l' m. intros l l' m H0 H1 H3 H4 k H5.
  eapply perm_next. apply H1. exact H0. exact H5. exact H3.
  (* dont understand why normal 'apply ... with' was failing *)
Qed.

(* We are now in a position to prove the symmetry of Permute *)
Lemma Permute_sym: forall (A:Type), symmetric (list A) Permute.
Proof.
  intro A. unfold symmetric.
  intros l m H. generalize H. elim H. auto. clear H m l.
  intros l l' m H0 H1 H2 H3. apply Transpose_first with (l':=l').
  apply Transpose_sym. exact H2. apply H1. exact H0.
Qed.

(* Permute is also a transitive relation on list A *)
Lemma Permute_trans: forall (A:Type), transitive (list A) Permute.
Proof.
  intros A. unfold transitive.
  intros l m k H. generalize H k. clear k. elim H. auto.
  clear H l m. intros l l' m H0 H1 H2 H3 k H4.
  apply H1. exact H0. apply Transpose_first with (l':=m).
  exact H2. exact H4.
Qed.

(* Two lists which are permutation of one another have same length *)
Lemma Permute_imp_eq_length: forall (A:Type)(l m:list A),
  Permute l m -> length l = length m.
Proof.
  intros A l m H. generalize H. elim H.
  clear H l m. intros. reflexivity.
  clear H l m. intros l l' m H0 H1 H2 H3. clear H3.
  apply eq_trans with (y:=length l').
  apply H1. exact H0. apply Transpose_imp_eq_length. exact H2.
Qed.

Lemma Permute_cons: forall (A:Type)(l m: list A)(a: A),
  Permute l m -> Permute (a::l) (a::m).
Proof.
  intros A l m a H. generalize H. generalize a. clear a. elim H.
    clear H l m. intros. apply perm_refl.
    clear H l m. intros l l' m H0 H1 H2 a H3.
  apply (Permute_trans A (a::l) (a::l') (a::m)). apply H1. exact H0.
  apply (perm_next (a::l') (a::l') (a::m)). apply perm_refl.
  apply Transpose_cons. exact H2.
Qed.

Definition SubSet {A:Type}(l m:list A) : Prop :=
  forall (x:A), In x l -> In x m.

Definition EqSet {A:Type}(l m: list A) : Prop :=
  SubSet l m /\ SubSet m l.

Lemma SubSet_refl: forall (A:Type), reflexive (list A) SubSet.
Proof.
  intros A. unfold reflexive. intro l. unfold SubSet. auto.
Qed.

Lemma SubSet_trans: forall (A: Type), transitive (list A) SubSet.
Proof.
  intros A. unfold transitive.
  intros l m k H0 H1. unfold SubSet. intros x H2.
  apply H1. apply H0. exact H2.
Qed.

Lemma Transpose_imp_SubSet: forall (A:Type),
  inclusion (list A) Transpose SubSet.
Proof.
  intros A. unfold inclusion.
  intros l m H. generalize H. elim H.
    clear H l m. intros. apply SubSet_refl.
    clear H l m. intros x y H0. clear H0. unfold SubSet.
      intros z H0. simpl. simpl in H0. elim H0.
        clear H0. intro H0. right. left. exact H0.
        clear H0. intro H0. elim H0. clear H0. intro H0. left. exact H0.
          apply False_ind.
    clear H l m. intros l m l1 l2 H0 H1 H2. clear H2. unfold SubSet.
      intros x H2. simpl. rewrite in_app_iff, in_app_iff.
      rewrite in_app_iff, in_app_iff in H2. elim H2.
        clear H2. intro H2. left. exact H2.
        clear H2. intro H2. elim H2. clear H2. intro H2. right. left.
          apply H1. exact H0. exact H2.
        clear H2. intro H2. right. right. exact H2.
Qed.

Lemma Transpose_imp_EqSet: forall (A:Type),
  inclusion (list A) Transpose EqSet.
Proof.
  intros A. unfold inclusion.
  intros l m H. unfold EqSet. split.
  apply Transpose_imp_SubSet. exact H.
  apply Transpose_imp_SubSet. apply Transpose_sym. exact H.
Qed.

Lemma Permute_imp_SubSet: forall (A:Type),
  inclusion (list A) Permute SubSet.
Proof.
  intros A. unfold inclusion.
  intros l m H. generalize H. elim H.
    clear H l m. intros. apply SubSet_refl.
    clear H l m. intros l l' m H0 H1 H2 H3. clear H3.
      apply (SubSet_trans A l l' m). apply H1. exact H0.
      apply Transpose_imp_SubSet. exact H2.
Qed.

Lemma Permute_imp_EqSet: forall (A:Type),
  inclusion (list A) Permute EqSet.
Proof.
  intros A. unfold inclusion.
  intros l m H. unfold EqSet. split.
  apply Permute_imp_SubSet. exact H.
  apply Permute_imp_SubSet. apply Permute_sym. exact H.
Qed.

Lemma Permute_cons_reverse: forall (A:Type)(l m:list A)(a:A),
  Permute (a::l) (a::m) -> Permute l m.
Proof.
  intros A l m a.
  cut (forall (l' m':list A),
    l' = a::l -> m' = a::m -> Permute l' m' -> Permute l m). eauto.
  intros l' m' Hl Hm H. generalize H Hl Hm.
  clear Hl Hm. generalize l m a. clear l m a. elim H.
    clear H l' m'. intros l m' m a H0 H1 H2. clear H0.
      rewrite H2 in H1. clear H2. injection H1. clear H1.
      intro H0. rewrite H0. apply perm_refl.
    clear H l' m'. intros l' k' m' H0 H1 H3 l m a H4 H5 H6.


Require Import Bool Arith ZArith List.

Import ListNotations.

(* EXAMPLES *)
(* The following function takes two arguments a and b
which are numbers of type nat and returns b + 2 * (a + b) *)
Definition f_ex (a b : nat) := b + 2 * (a + b).

(* When p is a pair, you can access its components by the "pattern-matching"
  construct illustrated in the following function. *)
Definition add_pair_components (p : nat * nat) :=
  match p with (a, b) => a + b end.

(* f_ex is a function with two arguments.  add_pair_components is a
  function with one argument, which is a pair. *)

(* END OF EXAMPLES *)

(* 1/ Define a function that takes two numbers as arguments and returns
  the sum of the squares of these numbers. *)
Definition sumsq (a b : nat) := a * a + b * b.

(* 2/ Define a function that takes 5 arguments a b c d e, which are all
   numbers and returns the sum of all these numbers. *)
Definition sum5 (a b c d e : nat) := a + b + c + d + e.

(* 3/ Define a function named add5 that takes a number as argument and returns
   this number plus 5. *)
Definition add5 := Nat.add 5.

(* The following should return 8 *)
Compute add5 3.

(* The following commands make it possible to find pre-defined functions
Search nat.
Search bool.
 *)

(* 4/ Write a function swap of type list nat -> list nat such that
  swap (a::b::l) = (b::a::l)  and
  swap l' = l' if l' has less than 2 elements. *)
Definition swap (ns : list nat) : list nat
  := match ns with
     | [] | [_] => ns
     | n1 :: n2 :: ns' => n2 :: n1 :: ns'
     end.

Theorem swap_long (a b : nat) (l : list nat) : swap (a::b::l) = (b::a::l).
Proof. reflexivity. Qed.

Theorem swap_short (ns : list nat) : length ns < 2 -> swap ns = ns.
Proof.
  intro H.
  destruct ns; try reflexivity.
  destruct ns; try reflexivity.
  repeat apply lt_S_n in H.
  now apply Nat.nlt_0_r in H.
Qed.

(* 5/ Write a function proc2 of type list nat -> nat, such that
   proc2 (a::b::l) = (b + 3) and
   proc2 l' = 0 if l' has less than 2 elements.

   In other words, proc2 only processes the 2nd argument of the list and
   returns that number plus 3.  If there is no second argument to the list,
   proc2 returns 0.  *)
Definition proc2 (ns : list nat) : nat
  := match ns with
     | [] | [_] => 0
     | n1 :: n2 :: _  => n2 + 3
     end.

(* 6/ Write a function ms of type list nat -> list nat such that
      ms (a::b::...::nil) = a+2::b+2::...::nil
      For instance
      ms (2::3::5::nil) = (4::5::7::nil) *)
Fixpoint ms (ns : list nat) : list nat
  := match ns with
     | [] => []
     | n :: ns' => (n + 2) :: (ms ns')
     end.

Example ms_ex : ms (2::3::5::nil) = (4::5::7::nil).
Proof. reflexivity. Qed.

(* 7/ Write a function sorted of type list nat -> bool, such that
    sorted l = true exactly when the natural numbers in
   l are in increasing order. *)
Definition sorted (ns : list nat) : bool
  := let fix iter (n : nat) (ns : list nat)
         := match ns with
            | [] => true
            | n' :: ns' => (n <=? n') && iter n' ns'
            end
     in match ns with
        | [] => true
        | n :: ns' => iter n ns'
        end.

Example sorted_ex : sorted [1; 3; 3; 5] = true.
Proof. reflexivity. Qed.

Example sorted_ex2 : sorted [1; 3; 2; 3; 5] = false.
Proof. reflexivity. Qed.

Inductive sorted_p  : list nat -> Prop
  := sorted0 : sorted_p []
   | sorted1 (n : nat) : sorted_p [n]
   | sorted_n (n0 n1 : nat) (ns : list nat) :
       n0 <= n1
       -> sorted_p (n1 :: ns)
       -> sorted_p (n0 :: n1 :: ns).

Example sorted_p_ex : sorted_p [1; 3; 3; 5].
Proof. auto using sorted_p with arith. Qed.

Example sorted_p_ex2 : ~ sorted_p [1; 3; 2; 3; 5].
Proof.
  intro H. inversion H. inversion H4.
  now apply Nat.nle_succ_diag_l in H7.
Qed.

Theorem iff_true_r (A : Prop) : A -> (A <-> True).
Proof. firstorder. Qed.

Theorem iff_true_l (A : Prop) : A -> (True <-> A).
Proof. firstorder. Qed.

Theorem proven_iff (A B : Prop) : A -> B -> (A <-> B).
Proof. firstorder. Qed.

Theorem sorted_correct (ns : list nat) : sorted ns = true <-> sorted_p ns.
Proof.
  induction ns as [| n0 ns0 IH]; try destruct ns0 as [| n1 ns1];
    try ( apply proven_iff; try reflexivity; constructor ).
  split; intro H; inversion H.
  - apply andb_prop in H1 as [H1 H2].
    apply Nat.leb_le in H1 as H1'.
    apply sorted_n; try assumption.
    apply IH. assumption.
  - subst n2 n3 ns. apply Nat.leb_le in H2 as H2'.
    assert (sorted (n1 :: ns1) = true) as Hs.
    { apply IH. assumption. }
    simpl. apply andb_true_intro; split; assumption.
Qed.

(* 8/ Write a function p2 of type nat -> nat such that
    p2 n = 2 ^ n *)
Fixpoint p2 (n : nat) : nat
  := match n with
     | O => 1
     | S n' => 2 * (p2 n')
     end.

Example p2_ex : p2 3 = 8.
Proof. reflexivity. Qed.

Theorem p2_correct (n : nat) : Nat.pow 2 n = p2 n.
Proof.
  induction n as [| n' IH]; try reflexivity.
  simpl. rewrite <- IH. ring.
Qed.

(* 9/ Write a function salt of type nat -> nat -> nat such that
   salt x n = x^n - x^(n-1) + x^(n-2) .... + 1 or -1, if x <> 0,
   depending on the parity of n, thus
   salt x 3 = x^3 - x^2 + x - 1
   salt x 4 = x^4 - x^3 + x^2 - x + 1
   salt 2 3 = 5

   You may have to define auxiliary functions. *)
Fixpoint salt0 (x n : nat) : nat
  := match n with
     | O => 1
     | S n' => x^n - (salt0 x n')
     end.
Example salt0_is_wrong_ex : salt0 0 2 <> 1.
Proof. simpl. apply O_S. Qed.

Fixpoint salt (x n : nat) : nat
  := match n with
     | O => 1
     | 1 => x - 1
     | S (S n') => x^n - x^(S n') + (salt x n')
     end.

Example salt_ex1 (x : nat) : salt x 3 = x^3 - x^2 + x - 1.
Proof.
  cbv beta delta [salt] iota.
  pose (gt_0_eq x) as H.
  destruct H as [neq | eq]; try ( subst x; reflexivity ).
  apply gt_le_S in neq.
  rewrite Nat.add_sub_assoc; try assumption.
  reflexivity.
Qed.

Example salt_ex2 (x : nat) : salt x 4 = x^4 - x^3 + x^2 - x + 1.
Proof.
  cbv beta delta [salt] iota.
  pose (gt_0_eq x) as H.
  destruct H as [neq | eq]; try ( subst x; reflexivity ).
  rewrite Nat.add_assoc. rewrite Nat.pow_1_r.
  rewrite Nat.add_sub_assoc; try reflexivity.
  rewrite Nat.pow_2_r. rewrite <- Nat.mul_1_l at 1.
  apply Nat.mul_le_mono_r. apply gt_le_S. assumption.
Qed.

Example salt_ex3 : salt 2 3 = 5.
Proof. reflexivity. Qed.

Fixpoint salt2_aux (x m acc : nat) (p : bool) : nat
  := match m with
     | O => if p then acc + 1 else acc - 1
     | S m' => let s := x^m in
               let acc' := if p then (acc + s) else (acc - s)
               in salt2_aux x m' acc' (negb p)
     end.

Definition salt2 (x n : nat) : nat
  := salt2_aux x n 0 true.

Example salt2_ex1 (x : nat) : salt2 x 3 = x^3 - x^2 + x - 1.
Proof.
  unfold salt2. simpl. rewrite Nat.mul_1_r. reflexivity.
Qed.

Example salt2_ex2 (x : nat) : salt2 x 4 = x^4 - x^3 + x^2 - x + 1.
Proof.
  unfold salt2. simpl. rewrite Nat.mul_1_r. reflexivity.
Qed.

Example salt2_ex3 : salt2 2 3 = 5.
Proof. reflexivity. Qed.

Definition salt_eq (x n : nat) := salt x n = salt2 x n.
Definition salt2_aux_eq (x m : nat)
  := forall acc : nat,
    salt2_aux x m acc true = acc + salt2_aux x m 0 true.

Lemma salt2_aux_acc_lem (x m : nat)
  : 0 < x
    -> (forall m' : nat, m' < m -> salt2_aux_eq x m')
    -> salt2_aux_eq x m.
Proof.
  intros xneq IH.
  destruct m as [| m0]; unfold salt2_aux_eq; try reflexivity.
  intro acc. simpl.
  destruct m0 as [| m1].
  - simpl. repeat rewrite Nat.mul_1_r.
    rewrite Nat.add_sub_assoc; try reflexivity.
    apply lt_le_S. assumption.
  - simpl. rewrite IH; try auto with arith.
    symmetry. rewrite IH; try auto with arith.
    rewrite Nat.add_assoc, Nat.add_sub_assoc; try reflexivity.
    apply Nat.mul_le_mono_l. rewrite <- Nat.mul_1_l at 1.
    apply Nat.mul_le_mono_r. apply lt_le_S. assumption.
Qed.

Lemma salt2_aux_acc (x m : nat) : 0 < x -> salt2_aux_eq x m.
Proof.
  intro xneq. apply (lt_wf_ind m (salt2_aux_eq x)).
  intros m' H. apply salt2_aux_acc_lem; assumption.
Qed.

Lemma salt2_SS (x n : nat)
  : 0 < x -> salt2 x (S (S n)) = x^(S (S n)) - x^(S n) + salt2 x n.
Proof.
  intro xneq. unfold salt2. simpl.
  rewrite salt2_aux_acc; try assumption.
  reflexivity.
Qed.

Lemma salt_eq_lem (x n : nat)
  : (forall m, m < n -> salt_eq x m) -> salt_eq x n.
Proof.
  intro IH.
  destruct n as [| n0]; try reflexivity.
  destruct n0 as [| n1].
  - unfold salt_eq, salt2. simpl. auto with arith.
  - unfold salt_eq.
    pose (zerop x) as Hx. destruct Hx as [eq | neq].
    + (* x = 0 *) subst x. unfold salt2. simpl.
      apply IH. auto with arith.
    + (* 0 < x *)
      replace (salt x (S (S n1)))
        with (x^(S (S n1)) - x^(S n1) + salt x n1);
        try reflexivity.
      replace (salt2 x (S (S n1)))
        with (x^(S (S n1)) - x^(S n1) + salt2 x n1).
      * rewrite Nat.add_cancel_l. apply IH.
        auto with arith.
      * unfold salt2. simpl.
        symmetry. rewrite salt2_aux_acc; try assumption.
        reflexivity.
Qed.

Theorem salt_is_salt2 (x n : nat) : salt_eq x n.
Proof.
  apply (lt_wf_ind n (salt_eq x)).
  apply (salt_eq_lem x).
Qed.

(* 10/  Consider the following definition *)

Inductive btree : Type
  := leaf | bnode (n : nat) (t1 t2 : btree).

(* write a function that list the labels of a tree by infix order *)
(** you may use the concatenation function app on lists
  (also written l1 ++ l2 ) *)

Fixpoint list_btns (t : btree) : list nat
  := match t with
     | leaf => []
     | bnode n t1 t2 => list_btns t1 ++ (n :: list_btns t2)
     end.

Example btree_ex
  := let t3 := bnode 3 (bnode 4 leaf leaf) leaf
     in let t5 := bnode 5 leaf (bnode 6 leaf leaf)
     in let t2 := bnode 2 t3 t5
     in bnode 1 leaf t2.
Example list_btns_ex : list_btns btree_ex = [1; 4; 3; 2; 5; 6].
Proof. unfold btree_ex. reflexivity. Qed.

(* write a boolean function that checks whether a tree is a binary
search tree *)
Fixpoint rightmost (t : btree) : option nat
  := match t with
     | leaf => None
     | bnode n _ leaf => Some n
     | bnode n _ t2 => rightmost t2
     end.

Lemma rightmost_is_none_on_leaf_only (t : btree)
  : rightmost t = None <-> t = leaf.
Proof.
  induction t as [| n t1 _ t2 IH]; try easy.
  simpl. destruct t2 as [| n2 t21 t22]; try easy.
  rewrite IH. easy.
Qed.

Fixpoint leftmost (t : btree) : option nat
  := match t with
     | leaf => None
     | bnode n leaf _ => Some n
     | bnode n t1 _ => leftmost t1
     end.

Lemma leftmost_is_none_on_leaf_only (t : btree)
  : leftmost t = None <-> t = leaf.
Proof.
  induction t as [| n t1 IH t2 _]; try easy.
  simpl. destruct t1 as [| n1 t11 t12]; try easy.
  rewrite IH. easy.
Qed.

Fixpoint is_bst (t : btree) : bool
  := match t with
     | leaf => true
     | bnode n t1 t2 => is_bst t1 && is_bst t2
                        && match rightmost t1 with
                           | None => true
                           | Some n1 => n1 <? n
                           end
                        && match leftmost t2 with
                           | None => true
                           | Some n2 => n <? n2
                           end
     end.

Example is_bst_ex1: is_bst btree_ex = false.
Proof. unfold btree_ex. reflexivity. Qed.

Example bst_ex
  := let t6 := bnode 6 (bnode 4 leaf leaf) (bnode 7 leaf leaf)
     in let t3 := bnode 3 (bnode 1 leaf leaf) t6
     in let t10 := bnode 10 leaf (bnode 14 (bnode 13 leaf leaf) leaf)
     in bnode 8 t3 t10.

Example is_bst_ex2: is_bst bst_ex = true.
Proof. unfold bst_ex. reflexivity. Qed.

Example nbst_ex
  := let t6 := bnode 6 (bnode 4 leaf leaf) (bnode 9 leaf leaf)
     in let t3 := bnode 3 (bnode 1 leaf leaf) t6
     in let t10 := bnode 10 leaf (bnode 14 (bnode 13 leaf leaf) leaf)
     in bnode 8 t3 t10.

Example is_bst_ex3: is_bst nbst_ex = false.
Proof. unfold bst_ex. reflexivity. Qed.


(** * Lists: Working with Structured Data *)

From LF Require Export Induction.
Module NatList.

(* ################################################################# *)
(** * Pairs of Numbers *)

(** In an [Inductive] type definition, each constructor can take
    any number of arguments -- none (as with [true] and [O]), one (as
    with [S]), or more than one (as with [nybble], and here): *)

Inductive natprod : Type :=
| pair (n1 n2 : nat).

(** This declaration can be read: "There is just one way to
    construct a pair of numbers: by applying the constructor [pair] to
    two arguments of type [nat]." *)

Check (pair 3 5).

(** Here are simple functions for extracting the first and
    second components of a pair. *)

Definition fst (p : natprod) : nat :=
  match p with
  | pair x y => x
  end.

Definition snd (p : natprod) : nat :=
  match p with
  | pair x y => y
  end.

Compute (fst (pair 3 5)).
(* ===> 3 *)

(** Since pairs will be used heavily, it is nice to be able to
    write them with the standard mathematical notation [(x,y)] instead
    of [pair x y].  We can tell Coq to allow this with a [Notation]
    declaration. *)

Notation "( x , y )" := (pair x y).

(** The new pair notation can be used both in expressions and in
    pattern matches. *)

Compute (fst (3,5)).

Definition fst' (p : natprod) : nat :=
  match p with
  | (x,y) => x
  end.

Definition snd' (p : natprod) : nat :=
  match p with
  | (x,y) => y
  end.

Definition swap_pair (p : natprod) : natprod :=
  match p with
  | (x,y) => (y,x)
  end.

(** Note that pattern-matching on a pair (with parentheses: [(x, y)])
    is not to be confused with the "multiple pattern" syntax
    (with no parentheses: [x, y]) that we have seen previously.

    The above examples illustrate pattern matching on a pair with
    elements [x] and [y], whereas [minus] below (taken from
    [Basics]) performs pattern matching on the values [n]
    and [m].

       Fixpoint minus (n m : nat) : nat :=
         match n, m with
         | O   , _    => O    why?
         | S _ , O    => n     or m ?
         | S n', S m' => minus n' m'
         end.

    The distinction is minor, but it is worth knowing that they
    are not the same. For instance, the following definitions are
    ill-formed:

        (* Can't match on a pair with multiple patterns: *)

        Definition bad_fst (p : natprod) : nat :=
          match p with
          | x, y => x                 missing paranthesis around x,y
          end.

        (* Can't match on multiple values with pair patterns: *)

        Definition bad_minus (n m : nat) : nat :=
          match n, m with      having unnecessary paranthesis
          | (O   , _   ) => O
          | (S _ , O   ) => n or m
          | (S n', S m') => bad_minus n' m'
          end.
*)

(** Let's try to prove a few simple facts about pairs.

    If we state things in a slightly peculiar way, we can complete
    proofs with just reflexivity (and its built-in simplification): *)

Theorem surjective_pairing' : forall (n m : nat),
  (n,m) = (fst (n,m), snd (n,m)).
Proof.
  reflexivity.  Qed.

(** But [reflexivity] is not enough if we state the lemma in a more
    natural way: *)

Theorem surjective_pairing_stuck : forall (p : natprod),
  p = (fst p, snd p).
Proof.
  simpl. (* Doesn't reduce anything! *)
Abort.

(** We have to expose the structure of [p] so that [simpl] can
    perform the pattern match in [fst] and [snd].  We can do this with
    [destruct]. *)

Theorem surjective_pairing : forall (p : natprod),
  p = (fst p, snd p).
Proof.
  intros p.  destruct p as [n m].  simpl.  reflexivity.  Qed.

(** Notice that, unlike its behavior with [nat]s, where it
    generates two subgoals, [destruct] generates just one subgoal
    here.  That's because [natprod]s can only be constructed in one
    way. *)

(** **** Exercise: 1 star, standard (snd_fst_is_swap)  *)
Theorem snd_fst_is_swap : forall (p : natprod),
  (snd p, fst p) = swap_pair p.
Proof.
  intros p. destruct p as [n m]. simpl. reflexivity. Qed.
(** [] *)

(* ################################################################# *)
(** * Lists of Numbers *)

(** Generalizing the definition of pairs, we can describe the
    type of _lists_ of numbers like this: "A list is either the empty
    list or else a pair of a number and another list." *)

Inductive natlist : Type :=
  | nil
  | cons (n : nat) (l : natlist).

(** For example, here is a three-element list: *)

Definition mylist := cons 1 (cons 2 (cons 3 nil)).

(** As with pairs, it is more convenient to write lists in
    familiar programming notation.  The following declarations
    allow us to use [::] as an infix [cons] operator and square
    brackets as an "outfix" notation for constructing lists. *)

Notation "x :: l" := (cons x l)
                     (at level 60, right associativity).
Notation "[ ]" := nil.
Notation "[ x ; .. ; y ]" := (cons x .. (cons y nil) ..).

(** It is not necessary to understand the details of these
    declarations, but here is roughly what's going on in case you are
    interested.  The [right associativity] annotation tells Coq how to
    parenthesize expressions involving multiple uses of [::] so that,
    for example, the next three declarations mean exactly the same
    thing: *)

Definition mylist1 := 1 :: (2 :: (3 :: nil)).
Definition mylist2 := 1 :: 2 :: 3 :: nil.
Definition mylist3 := [1;2;3].

(** The [at level 60] part tells Coq how to parenthesize
    expressions that involve both [::] and some other infix operator.
    For example, since we defined [+] as infix notation for the [plus]
    function at level 50,

  Notation "x + y" := (plus x y)
                      (at level 50, left associativity).

    the [+] operator will bind tighter than [::], so [1 + 2 :: [3]]
    will be parsed, as we'd expect, as [(1 + 2) :: [3]] rather than
    [1 + (2 :: [3])].

    (Expressions like "[1 + 2 :: [3]]" can be a little confusing when
    you read them in a [.v] file.  The inner brackets, around 3, indicate
    a list, but the outer brackets, which are invisible in the HTML
    rendering, are there to instruct the "coqdoc" tool that the bracketed
    part should be displayed as Coq code rather than running text.)

    The second and third [Notation] declarations above introduce the
    standard square-bracket notation for lists; the right-hand side of
    the third one illustrates Coq's syntax for declaring n-ary
    notations and translating them to nested sequences of binary
    constructors. *)

(* ----------------------------------------------------------------- *)
(** *** Repeat *)

(** A number of functions are useful for manipulating lists.
    For example, the [repeat] function takes a number [n] and a
    [count] and returns a list of length [count] where every element
    is [n]. *)

Fixpoint repeat (n count : nat) : natlist :=
  match count with
  | O => nil
  | S count' => n :: (repeat n count')
  end.

(* ----------------------------------------------------------------- *)
(** *** Length *)

(** The [length] function calculates the length of a list. *)

Fixpoint length (l:natlist) : nat :=
  match l with
  | nil => O
  | h :: t => S (length t)
  end.

(* ----------------------------------------------------------------- *)
(** *** Append *)

(** The [app] function concatenates (appends) two lists. *)

Fixpoint app (l1 l2 : natlist) : natlist :=
  match l1 with
  | nil    => l2
  | h :: t => h :: (app t l2)
  end.

(** Since [app] will be used extensively in what follows, it is
    again convenient to have an infix operator for it. *)

Notation "x ++ y" := (app x y)
                     (right associativity, at level 60).

Example test_app1:             [1;2;3] ++ [4;5] = [1;2;3;4;5].
Proof. reflexivity.  Qed.
Example test_app2:             nil ++ [4;5] = [4;5].
Proof. reflexivity.  Qed.
Example test_app3:             [1;2;3] ++ nil = [1;2;3].
Proof. reflexivity.  Qed.

(* ----------------------------------------------------------------- *)
(** *** Head (With Default) and Tail *)

(** Here are two smaller examples of programming with lists.
    The [hd] function returns the first element (the "head") of the
    list, while [tl] returns everything but the first element (the
    "tail").  Since the empty list has no first element, we must pass
    a default value to be returned in that case.  *)

Definition hd (default:nat) (l:natlist) : nat :=
  match l with
  | nil => default
  | h :: t => h
  end.

Definition tl (l:natlist) : natlist :=
  match l with
  | nil => nil
  | h :: t => t
  end.

Example test_hd1:             hd 0 [1;2;3] = 1.
Proof. reflexivity.  Qed.
Example test_hd2:             hd 0 [] = 0.
Proof. reflexivity.  Qed.
Example test_tl:              tl [1;2;3] = [2;3].
Proof. reflexivity.  Qed.

(* ----------------------------------------------------------------- *)
(** *** Exercises *)

(** **** Exercise: 2 stars, standard, recommended (list_funs)

    Complete the definitions of [nonzeros], [oddmembers], and
    [countoddmembers] below. Have a look at the tests to understand
    what these functions should do. *)

Fixpoint nonzeros (l:natlist) : natlist :=
 match l with
   nil => nil
  |h::t =>
        match h with
        | 0 => nonzeros (t)
        | _ => h :: nonzeros (t)
        end
 end.

Example test_nonzeros:
  nonzeros [0;1;0;2;3;0;0] = [1;2;3].
  Proof. reflexivity. Qed.

Fixpoint iseven (n:nat) : bool :=
  match n with
  | O        => true
  | S O      => false
  | S (S n') => iseven (n')
end.

Fixpoint oddmembers (l:natlist) : natlist :=
  match l with
   nil => nil
  |h::t =>
        match iseven(h) with
        |true => oddmembers (t)
        |false => h :: oddmembers (t)
        end
  end.

Example test_oddmembers:
  oddmembers [0;1;0;2;3;0;0] = [1;3].
  Proof. reflexivity. Qed.

Fixpoint countmembers (l:natlist) : nat :=
 match l with
 | [] => 0
 | h::t => 1 + countmembers(t)
 end.

Definition countoddmembers (l:natlist) : nat :=
  countmembers(oddmembers(l)).

Example test_countoddmembers1:
  countoddmembers [1;0;3;1;4;5] = 4.
  Proof. reflexivity. Qed.

Example test_countoddmembers2:
  countoddmembers [0;2;4] = 0.
   Proof. reflexivity. Qed.

Example test_countoddmembers3:
  countoddmembers nil = 0.
   Proof. reflexivity. Qed.
(** [] *)

(** **** Exercise: 3 stars, advanced (alternate)

    Complete the definition of [alternate], which interleaves two
    lists into one, alternating between elements taken from the first
    list and elements from the second.  See the tests below for more
    specific examples.

    (Note: one natural and elegant way of writing [alternate] will
    fail to satisfy Coq's requirement that all [Fixpoint] definitions
    be "obviously terminating."  If you find yourself in this rut,
    look for a slightly more verbose solution that considers elements
    of both lists at the same time.  One possible solution involves
    defining a new kind of pairs, but this is not the only way.)  *)

Fixpoint alternate (l1 l2 : natlist) : natlist :=
  match l1 with
    | [] => l2
    | h1::t1 => match l2 with
                | [] => l1
                | h2::t2 => (app [h1;h2] (alternate t1 t2))
                end
    end.

Example test_alternate1:
  alternate [1;2;3] [4;5;6] = [1;4;2;5;3;6].
  Proof. reflexivity. Qed.

Example test_alternate2:
  alternate [1] [4;5;6] = [1;4;5;6].
  Proof. reflexivity. Qed.

Example test_alternate3:
  alternate [1;2;3] [4] = [1;4;2;3].
  Proof. reflexivity. Qed.

Example test_alternate4:
  alternate [] [20;30] = [20;30].
  Proof. reflexivity. Qed.
(** [] *)

(* ----------------------------------------------------------------- *)
(** *** Bags via Lists *)

(** A [bag] (or [multiset]) is like a set, except that each element
    can appear multiple times rather than just once.  One possible
    representation for a bag of numbers is as a list. *)

Definition bag := natlist.

(** **** Exercise: 3 stars, standard, recommended (bag_functions)

    Complete the following definitions for the functions
    [count], [sum], [add], and [member] for bags. *)

Fixpoint count (v:nat) (s:bag) : nat :=
  match s with
  | [] => 0
  | h::t => match v =? h with
            | true => 1 + (count v t)
            | false => (count v t)
            end
  end.

(** All these proofs can be done just by [reflexivity]. *)

Example test_count1:              count 1 [1;2;3;1;4;1] = 3.
Proof. reflexivity. Qed.
Example test_count2:              count 6 [1;2;3;1;4;1] = 0.
Proof. reflexivity. Qed.

(** Multiset [sum] is similar to set [union]: [sum a b] contains all
    the elements of [a] and of [b].  (Mathematicians usually define
    [union] on multisets a little bit differently -- using max instead
    of sum -- which is why we don't use that name for this operation.)
    For [sum] we're giving you a header that does not give explicit
    names to the arguments.  Moreover, it uses the keyword
    [Definition] instead of [Fixpoint], so even if you had names for
    the arguments, you wouldn't be able to process them recursively.
    The point of stating the question this way is to encourage you to
    think about whether [sum] can be implemented in another way --
    perhaps by using functions that have already been defined.  *)

Definition sum : bag -> bag -> bag :=
    app.
     (*  app: bag->bag->bag  also works  *)

Example test_sum1:              count 1 (sum [1;2;3] [1;4;1]) = 3.
 Proof. reflexivity. Qed.

Definition add (v:nat) (s:bag) : bag:=
  (app ([v]:bag) (s) :bag).

Example test_add1:                count 1 (add 1 [1;4;1]) = 3.
 Proof. reflexivity. Qed.
Example test_add2:                count 5 (add 1 [1;4;1]) = 0.
 Proof. reflexivity. Qed.

Definition member (v:nat) (s:bag) : bool :=
  match (count v s) =? 0 with
  | true => false
  | false => true
  end.

Example test_member1:             member 1 [1;4;1] = true.
 Proof. reflexivity. Qed.

Example test_member2:             member 2 [1;4;1] = false.
 Proof. reflexivity. Qed.
(** [] *)

(** **** Exercise: 2 stars, standard, recommended (bag_theorem)

    Write down an interesting theorem [bag_theorem] about bags
    involving the functions [count] and [add], and prove it.  Note
    that, since this problem is somewhat open-ended, it's possible
    that you may come up with a theorem which is true, but whose proof
    requires techniques you haven't learned yet.  Feel free to ask for
    help if you get stuck! *)

Print bin_to_nat.

Theorem bag_theorem: forall v:nat, forall s:bag,
  count v (add v s) = 1 + (count v s).

    Proof.
      intros v s. induction s.
      -(* s = [] *) simpl. rewrite <- n_eqb_n. reflexivity.
      -(* s = s'  *) simpl. rewrite <- n_eqb_n. reflexivity.
    Qed.

(* Do not modify the following line: *)
Definition manual_grade_for_bag_theorem : option (nat*string) := None.
(* Note to instructors: For silly technical reasons, in this
   file (only) you will need to write [Some (Datatypes.pair 3 ""%string)]
   rather than [Some (3,""%string)] to enter your grade and comments.

    [] *)

(* ################################################################# *)
(** * Reasoning About Lists *)

(** As for numbers, simple facts about list-processing functions
    can sometimes be proved entirely by simplification.  For example,
    the simplification performed by [reflexivity] is enough for this
    theorem... *)

Theorem nil_app : forall l:natlist,
  [] ++ l = l.
Proof. reflexivity. Qed.

(** ...because the [[]] is substituted into the
    "scrutinee" (the expression whose value is being "scrutinized" by
    the match) in the definition of [app], allowing the match itself
    to be simplified. *)

(** Also, as with numbers, it is sometimes helpful to perform case
    analysis on the possible shapes (empty or non-empty) of an unknown
    list. *)

Theorem tl_length_pred : forall l:natlist,
  pred (length l) = length (tl l).
Proof.
  intros l. destruct l as [| n l'].
  - (* l = nil *)
    reflexivity.
  - (* l = cons n l' *)
    reflexivity.  Qed.

(** Here, the [nil] case works because we've chosen to define
    [tl nil = nil]. Notice that the [as] annotation on the [destruct]
    tactic here introduces two names, [n] and [l'], corresponding to
    the fact that the [cons] constructor for lists takes two
    arguments (the head and tail of the list it is constructing). *)

(** Usually, though, interesting theorems about lists require
    induction for their proofs. *)

(* ----------------------------------------------------------------- *)
(** *** Micro-Sermon *)

(** Simply _reading_ proof scripts will not get you very far!  It is
    important to step through the details of each one using Coq and
    think about what each step achieves.  Otherwise it is more or less
    guaranteed that the exercises will make no sense when you get to
    them.  'Nuff said. *)

(* ================================================================= *)
(** ** Induction on Lists *)

(** Proofs by induction over datatypes like [natlist] are a
    little less familiar than standard natural number induction, but
    the idea is equally simple.  Each [Inductive] declaration defines
    a set of data values that can be built up using the declared
    constructors: a boolean can be either [true] or [false]; a number
    can be either [O] or [S] applied to another number; a list can be
    either [nil] or [cons] applied to a number and a list.

    Moreover, applications of the declared constructors to one another
    are the _only_ possible shapes that elements of an inductively
    defined set can have, and this fact directly gives rise to a way
    of reasoning about inductively defined sets: a number is either
    [O] or else it is [S] applied to some _smaller_ number; a list is
    either [nil] or else it is [cons] applied to some number and some
    _smaller_ list; etc. So, if we have in mind some proposition [P]
    that mentions a list [l] and we want to argue that [P] holds for
    _all_ lists, we can reason as follows:

      - First, show that [P] is true of [l] when [l] is [nil].

      - Then show that [P] is true of [l] when [l] is [cons n l'] for
        some number [n] and some smaller list [l'], assuming that [P]
        is true for [l'].

    Since larger lists can only be built up from smaller ones,
    eventually reaching [nil], these two arguments together establish
    the truth of [P] for all lists [l].  Here's a concrete example: *)

Theorem app_assoc : forall l1 l2 l3 : natlist,
  (l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
Proof.
  intros l1 l2 l3. induction l1 as [| n l1' IHl1'].  (*    <----   WHAT?   *)
                                                     (* and if induction must
                                                        be done on n+1, why n::l'
                                                     *)
  - (* l1 = nil *)
    reflexivity.
  - (* l1 = cons n l1' *)
    simpl. rewrite -> IHl1'. reflexivity.
Qed.

(** Notice that, as when doing induction on natural numbers, the
    [as...] clause provided to the [induction] tactic gives a name to
    the induction hypothesis corresponding to the smaller list [l1']
    in the [cons] case. Once again, this Coq proof is not especially
    illuminating as a static document -- it is easy to see what's
    going on if you are reading the proof in an interactive Coq
    session and you can see the current goal and context at each
    point, but this state is not visible in the written-down parts of
    the Coq proof.  So a natural-language proof -- one written for
    human readers -- will need to include more explicit signposts; in
    particular, it will help the reader stay oriented if we remind
    them exactly what the induction hypothesis is in the second
    case. *)

(** For comparison, here is an informal proof of the same theorem. *)

(** _Theorem_: For all lists [l1], [l2], and [l3],
   [(l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3)].

   _Proof_: By induction on [l1].

   - First, suppose [l1 = []].  We must show

       ([] ++ l2) ++ l3 = [] ++ (l2 ++ l3),

     which follows directly from the definition of [++].

   - Next, suppose [l1 = n::l1'], with

       (l1' ++ l2) ++ l3 = l1' ++ (l2 ++ l3)

     (the induction hypothesis). We must show

       ((n :: l1') ++ l2) ++ l3 = (n :: l1') ++ (l2 ++ l3).

     By the definition of [++], this follows from

       n :: ((l1' ++ l2) ++ l3) = n :: (l1' ++ (l2 ++ l3)),

     which is immediate from the induction hypothesis.  [] *)

(* ----------------------------------------------------------------- *)
(** *** Reversing a List *)

(** For a slightly more involved example of inductive proof over
    lists, suppose we use [app] to define a list-reversing function
    [rev]: *)

Fixpoint rev (l:natlist) : natlist :=
  match l with
  | nil    => nil
  | h :: t => rev t ++ [h]
  end.

Example test_rev1:            rev [1;2;3] = [3;2;1].
Proof. reflexivity.  Qed.
Example test_rev2:            rev nil = nil.
Proof. reflexivity.  Qed.

(* ----------------------------------------------------------------- *)
(** *** Properties of [rev] *)

(** Now, for something a bit more challenging than the proofs
    we've seen so far, let's prove that reversing a list does not
    change its length.  Our first attempt gets stuck in the successor
    case... *)

Theorem rev_length_firsttry : forall l : natlist,
  length (rev l) = length l.
Proof.
  intros l. induction l as [| n l' IHl'].
  - (* l = [] *)
    reflexivity.
  - (* l = n :: l' *)
    (* This is the tricky case.  Let's begin as usual
       by simplifying. *)
    simpl.
    (* Now we seem to be stuck: the goal is an equality
       involving [++], but we don't have any useful equations
       in either the immediate context or in the global
       environment!  We can make a little progress by using
       the IH to rewrite the goal... *)
    rewrite <- IHl'.
    (* ... but now we can't go any further. *)
Abort.

(** So let's take the equation relating [++] and [length] that
    would have enabled us to make progress and state it as a separate
    lemma. *)

Theorem app_length : forall l1 l2 : natlist,
  length (l1 ++ l2) = (length l1) + (length l2).
Proof.
  (* WORKED IN CLASS *)
  intros l1 l2. induction l1 as [| n l1' IHl1'].
  - (* l1 = nil *)
    reflexivity.
  - (* l1 = cons *)
    simpl. rewrite -> IHl1'. reflexivity.
Qed.

(** Note that, to make the lemma (Theorem?) as general as possible, we
    quantify over _all_ [natlist]s, not just those that result from an
    application of [rev].  This should seem natural, because the truth
    of the goal clearly doesn't depend on the list having been
    reversed.  Moreover, it is easier to prove the more general
    property. *)

(** Now we can complete the original proof. *)

Theorem rev_length : forall l : natlist,
  length (rev l) = length l.
Proof.
  intros l. induction l as [| n l' IHl'].
  - (* l = nil *)
    reflexivity.
  - (* l = cons *)
    simpl. rewrite -> app_length, plus_comm.
    simpl. rewrite -> IHl'. reflexivity.
Qed.

(** For comparison, here are informal proofs of these two theorems:

    _Theorem_: For all lists [l1] and [l2],
       [length (l1 ++ l2) = length l1 + length l2].

    _Proof_: By induction on [l1].

    - First, suppose [l1 = []].  We must show

        length ([] ++ l2) = length [] + length l2,

      which follows directly from the definitions of
      [length] and [++].

            (*            need explanation ^^        *)

    - Next, suppose [l1 = n::l1'], with

        length (l1' ++ l2) = length l1' + length l2.

      We must show

        length ((n::l1') ++ l2) = length (n::l1') + length l2).

      This follows directly from the definitions of [length] and [++]
      together with the induction hypothesis. [] *)

              (*            need explanation ^^        *)

(** _Theorem_: For all lists [l], [length (rev l) = length l].

    _Proof_: By induction on [l].

      - First, suppose [l = []].  We must show

          length (rev []) = length [],

        which follows directly from the definitions of [length]
        and [rev].

      - Next, suppose [l = n::l'], with

          length (rev l') = length l'.

        We must show

          length (rev (n :: l')) = length (n :: l').

        By the definition of [rev], this follows from

          length ((rev l') ++ [n]) = S (length l')

        which, by the previous lemma (Theoram?), is the same as

          length (rev l') + length [n] = S (length l').

        This follows directly from the induction hypothesis and the
        definition of [length]. [] *)

(** The style of these proofs is rather longwinded and pedantic (concerned
with minor detals).
    After the first few, we might find it easier to follow proofs that
    give fewer details (which we can easily work out in our own minds or
    on scratch paper if necessary) and just highlight the non-obvious
    steps.  In this more compressed style, the above proof might look
    like this: *)

(** _Theorem_:
     For all lists [l], [length (rev l) = length l].

    _Proof_: First, observe that [length (l ++ [n]) = S (length l)]
     for any [l] (this follows by a straightforward induction on [l]).
     The main property again follows by induction on [l], using the
     observation together with the induction hypothesis in the case
     where [l = n'::l']. [] *)

(** Which style is preferable in a given situation depends on
    the sophistication of the expected audience and how similar the
    proof at hand is to ones that the audience will already be
    familiar with.  The more pedantic style is a good default for our
    present purposes. *)

(* ================================================================= *)
(** ** [Search] *)

(** We've seen that proofs can make use of other theorems we've
    already proved, e.g., using [rewrite].  But in order to refer to a
    theorem, we need to know its name!  Indeed, it is often hard even
    to remember what theorems have been proven, much less what they
    are called.

    Coq's [Search] command is quite helpful with this.  Typing [Search
    foo] into your .v file and evaluating this line will cause Coq to
    display a list of all theorems involving [foo].  For example, try
    uncommenting the following line to see a list of theorems that we
    have proved about [rev]: *)

(** Keep [Search] in mind as you do the following exercises and
    throughout the rest of the book; it can save you a lot of time!

    If you are using ProofGeneral, you can run [Search] with
    [C-c C-a C-a]. Pasting its response into your buffer can be
    accomplished with [C-c C-;]. *)

(* ================================================================= *)
(** ** List Exercises, Part 1 *)

(** **** Exercise: 3 stars, standard (list_exercises)

    More practice with lists: *)

Theorem app_nil_r : forall l : natlist,
  l ++ [] = l.
Proof.
  intros l. induction l as [| n l' IHl'].
  - (* l=[] *) simpl. reflexivity.
  - (* l = n::l' *) simpl. rewrite IHl'. reflexivity.
Qed.

Theorem rev_app_distr: forall l1 l2 : natlist,
  rev (l1 ++ l2) = rev l2 ++ rev l1.

Proof.
  intros l1 l2. induction l1 as [| n l1' IHl1'].
  -(* l1 = [] *) simpl. rewrite app_nil_r. reflexivity.
  -(* l1 = n :: l1'*)  simpl. rewrite -> IHl1'.
                       rewrite app_assoc.   (* right associative by default*)
                       reflexivity.
Qed.

Theorem rev_involutive : forall l : natlist,
  rev (rev l) = l.
Proof.
  intros l. induction l as [| n l' IHl'].
  - (*l=[]*) simpl. reflexivity.
  - (* l = n::l' *) simpl. rewrite rev_app_distr. rewrite IHl'. simpl. reflexivity.
Qed.

(** There is a short solution to the next one.  If you find yourself
    getting tangled up, step back and try to look for a simpler
    way. *)

Theorem app_assoc4 : forall l1 l2 l3 l4 : natlist,
  l1 ++ (l2 ++ (l3 ++ l4)) = ((l1 ++ l2) ++ l3) ++ l4.
Proof.
  intros l1 l2 l3 l4. induction l1 as [| n l1 IHl1'].
  - (* l1=[] *) simpl. rewrite app_assoc. reflexivity.
  - (* l1 = n::l1' *) simpl. rewrite IHl1'. reflexivity.
Qed.

(** An exercise about your implementation of [nonzeros]: *)

(*         **********************************************        *)
Lemma nonzeros_app : forall l1 l2 : natlist,
  nonzeros (l1 ++ l2) = (nonzeros l1) ++ (nonzeros l2).
Proof.
  intros l1 l2. induction l1.
  - (* l1=[] *) simpl. reflexivity.
  - (* l1 = n::l1' *) simpl. rewrite IHl1.
                               destruct n.
                               -- (*n=0*)reflexivity.
                               -- (* n = S n' *) simpl. reflexivity.
Qed.
(*         **********************************************        *)

(** [] *)

(** **** Exercise: 2 stars, standard (eqblist)

    Fill in the definition of [eqblist], which compares
    lists of numbers for equality.  Prove that [eqblist l l]
    yields [true] for every list [l]. *)

Fixpoint eqblist (l1 l2 : natlist) : bool :=
  match l1 with
  | [] => match l2 with
          | [] => true
          | _  => false
          end
  | h::t => match l2 with
          | [] => false
          | h1 :: t1 => match h =? h1 with
                        | true =>  (eqblist t t1)
                        | false => false
                        end
          end
 end.

Example test_eqblist1 :
  (eqblist nil nil = true).
 Proof. reflexivity. Qed.

Example test_eqblist2 :
  eqblist [1;2;3] [1;2;3] = true.
 Proof. reflexivity. Qed.

Example test_eqblist3 :
  eqblist [1;2;3] [1;2;4] = false.
  Proof. reflexivity. Qed.

Theorem eqblist_refl : forall l:natlist,
  true = eqblist l l.
Proof.
  intros l.
  induction l as [| n l' IHl'].
  - (* l = [] *) simpl. reflexivity.
  - (* l = n l' *) simpl. rewrite <- IHl'. rewrite <- n_eqb_n. reflexivity.
Qed.

(** [] *)

(* ================================================================= *)
(** ** List Exercises, Part 2 *)

(** Here are a couple of little theorems to prove about your
    definitions about bags above. *)

(** **** Exercise: 1 star, standard (count_member_nonzero)  *)
Theorem count_member_nonzero : forall (s : bag),
  1 <=? (count 1 (1 :: s)) = true.
Proof.
  intros s. induction s as [| n s' IHl'].
  - (* s=[] *) simpl.  reflexivity.
  - (* s = h::t *) simpl. reflexivity.
 Qed.
(** [] *)

(** The following lemma about [leb] might help you in the next exercise. *)

Theorem leb_n_Sn : forall n,
  n <=? (S n) = true.
Proof.
  intros n. induction n as [| n' IHn'].
  - (* 0 *)
    simpl.  reflexivity.
  - (* S n' *)
    simpl.  rewrite IHn'.  reflexivity.
Qed.

(** Before doing the next exercise, make sure you've filled in the
   definition of [remove_one] above. *)
(** **** Exercise: 3 stars, advanced (remove_does_not_increase_count)  *)

(** **** Exercise: 3 stars, standard, optional (bag_more_functions)

    Here are some more [bag] functions for you to practice with. *)

(** When [remove_one] is applied to a bag without the number to
    remove, it should return the same bag unchanged.  (This exercise
    is optional, but students following the advanced track will need
    to fill in the definition of [remove_one] for a later
    exercise.) *)

Fixpoint remove_one (v:nat) (s:bag) : bag :=
  match s with
  | [] => []
  | h::t => match h =? v with
            | true => t
            | false => h :: (remove_one v t)
            end
  end.

Example test_remove_one1:
  count 5 (remove_one 5 [2;1;5;4;1]) = 0.
  Proof. reflexivity. Qed.

Example test_remove_one2:
  count 5 (remove_one 5 [2;1;4;1]) = 0.
  Proof. reflexivity. Qed.

Example test_remove_one3:
  count 4 (remove_one 5 [2;1;4;5;1;4]) = 2.
  Proof. reflexivity. Qed.

Example test_remove_one4:
  count 5 (remove_one 5 [2;1;5;4;5;1;4]) = 1.
  Proof. reflexivity. Qed.

 (* #################################################################

Theorem remove_does_not_increase_count: forall (s : bag),
  (count 0 (remove_one 0 s)) <=? (count 0 s) = true.
Proof.
  intros s. induction s as [| n s' IHs'].
  - (* s = [] *) simpl. reflexivity.
  - (* s = n s' *)
Qed.

 #################################################################   *)

(** [] *)

(** **** Exercise: 4 stars, advanced (rev_injective)

    Prove that the [rev] function is injective -- that is,

    forall (l1 l2 : natlist), rev l1 = rev l2 -> l1 = l2.

    (There is a hard way and an easy way to do this.) *)

(* #################################################################  *)
(* ######################     HELP      #######################  *)

Theorem rev_injective :
 forall (l1 l2 : natlist), rev l1 = rev l2 -> l1 = l2.

Proof.
 intros.

 assert ( H1 : rev (rev l1) = rev (rev l2)).
  {f_equal. rewrite H. reflexivity.  }

rewrite rev_involutive in H1.
rewrite rev_involutive in H1.
apply H1.

Qed.

(*  #################################################################   *)

(* Do not modify the following line: *)
Definition manual_grade_for_rev_injective : option (nat*string) := None.
(** [] *)

(* ################################################################# *)
(** * Options *)

(** Suppose we want to write a function that returns the [n]th
    element of some list.  If we give it type [nat -> natlist -> nat],
    then we'll have to choose some number to return when the list is
    too short... *)

Fixpoint nth_bad (l:natlist) (n:nat) : nat :=
  match l with
  | nil => 42  (* arbitrary! *)
  | a :: l' => match n =? O with
               | true => a
               | false => nth_bad l' (pred n)
               end
  end.

(** This solution is not so good: If [nth_bad] returns [42], we
    can't tell whether that value actually appears on the input
    without further processing. A better alternative is to change the
    return type of [nth_bad] to include an error value as a possible
    outcome. We call this type [natoption]. *)

Inductive natoption : Type :=
  | Some (n : nat)
  | None.

(** We can then change the above definition of [nth_bad] to
    return [None] when the list is too short and [Some a] when the
    list has enough members and [a] appears at position [n]. We call
    this new function [nth_error] to indicate that it may result in an
    error. *)

Fixpoint nth_error (l:natlist) (n:nat) : natoption :=
  match l with
  | nil => None
  | a :: l' => match n =? O with
               | true => Some a
               | false => nth_error l' (pred n)
               end
  end.

Example test_nth_error1 : nth_error [4;5;6;7] 0 = Some 4.
Proof. reflexivity. Qed.
Example test_nth_error2 : nth_error [4;5;6;7] 3 = Some 7.
Proof. reflexivity. Qed.
Example test_nth_error3 : nth_error [4;5;6;7] 9 = None.
Proof. reflexivity. Qed.

(** (In the HTML version, the boilerplate proofs of these
    examples are elided.  Click on a box if you want to see one.)

    This example is also an opportunity to introduce one more small
    feature of Coq's programming language: conditional
    expressions... *)

Fixpoint nth_error' (l:natlist) (n:nat) : natoption :=
  match l with
  | nil => None
  | a :: l' => if n =? O then Some a
               else nth_error' l' (pred n)
  end.

(** Coq's conditionals are exactly like those found in any other
    language, with one small generalization.  Since the boolean type
    is not built in, Coq actually supports conditional expressions over
    _any_ inductively defined type with exactly two constructors.  The
    guard is considered true if it evaluates to the first constructor
    in the [Inductive] definition and false if it evaluates to the
    second. *)

(** The function below pulls the [nat] out of a [natoption], returning
    a supplied default in the [None] case. *)

Definition option_elim (d : nat) (o : natoption) : nat :=
  match o with
  | Some n' => n'
  | None => d
  end.

(** **** Exercise: 2 stars, standard (hd_error)

    Using the same idea, fix the [hd] function from earlier so we don't
    have to pass a default element for the [nil] case.  *)

Definition hd_error (l : natlist) : natoption :=
  match l with
  |nil => None
  |h::t => Some h
  end.

Example test_hd_error1 : hd_error [] = None.
  Proof. reflexivity. Qed.

Example test_hd_error2 : hd_error [1] = Some 1.
  Proof. reflexivity. Qed.

Example test_hd_error3 : hd_error [5;6] = Some 5.
  Proof. reflexivity. Qed.
(** [] *)

End NatList.

(* ################################################################# *)
(** * Partial Maps *)

(** As a final illustration of how data structures can be defined in
    Coq, here is a simple _partial map_ data type, analogous to the
    map or dictionary data structures found in most programming
    languages. *)

(** First, we define a new inductive datatype [id] to serve as the
    "keys" of our partial maps. *)

Inductive id : Type :=
  | Id (n : nat).

(** Internally, an [id] is just a number.  Introducing a separate type
    by wrapping each nat with the tag [Id] makes definitions more
    readable and gives us the flexibility to change representations
    later if we wish. *)

(** We'll also need an equality test for [id]s: *)

Definition eqb_id (x1 x2 : id) :=
  match x1, x2 with
  | Id n1, Id n2 => n1 =? n2
  end.

(** **** Exercise: 1 star, standard (eqb_id_refl)  *)
Theorem eqb_id_refl : forall x, true = eqb_id x x.
Proof.
    intros x. destruct x. simpl. rewrite <- n_eqb_n. reflexivity.
Qed.

(** [] *)

(** Now we define the type of partial maps: *)

Module PartialMap.
Export NatList.

Inductive partial_map : Type :=
  | empty
  | record (i : id) (v : nat) (m : partial_map).

(** This declaration can be read: "There are two ways to construct a
    [partial_map]: either using the constructor [empty] to represent an
    empty partial map, or by applying the constructor [record] to
    a key, a value, and an existing [partial_map] to construct a
    [partial_map] with an additional key-to-value mapping." *)

(** The [update] function overrides the entry for a given key in a
    partial map by shadowing it with a new one (or simply adds a new
    entry if the given key is not already present). *)

Definition update (d : partial_map)
                  (x : id) (value : nat)
                  : partial_map :=
  record x value d.

(** Last, the [find] function searches a [partial_map] for a given
    key.  It returns [None] if the key was not found and [Some val] if
    the key was associated with [val]. If the same key is mapped to
    multiple values, [find] will return the first one it
    encounters. *)

Fixpoint find (x : id) (d : partial_map) : natoption :=
  match d with
  | empty         => None
  | record y v d' => if eqb_id x y
                     then Some v
                     else find x d'
  end.

(** **** Exercise: 1 star, standard (update_eq)  *)
Theorem update_eq :
  forall (d : partial_map) (x : id) (v: nat),
    find x (update d x v) = Some v.
Proof.
  intros. destruct x. simpl. rewrite <- n_eqb_n. reflexivity.
Qed.
(** [] *)

(** **** Exercise: 1 star, standard (update_neq)  *)
Theorem update_neq :
  forall (d : partial_map) (x y : id) (o: nat),
    eqb_id x y = false -> find x (update d y o) = find x d.
Proof.

intros. unfold update. simpl. rewrite H. reflexivity.
Qed.

(** [] *)
End PartialMap.

(** **** Exercise: 2 stars, standard (baz_num_elts)

    Consider the following inductive definition: *)

Inductive baz : Type :=
  | Baz1 (x : baz)
  | Baz2 (y : baz) (b : bool).

(** How _many_ elements does the type [baz] have? (Explain in words,
    in a comment.)    type baz has infinitely many elements because each Baz2 can take
 a Baz2 as a passing argument *)

(* Do not modify the following line: *)
Definition manual_grade_for_baz_num_elts : option (nat*string) := None.
(** [] *)

(* Wed Jan 9 12:02:44 EST 2019 *)