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

From LF Require Export Induction.

Theorem beq_nat_refl : forall n : nat, n =? n = true.
Proof.
  induction n as [|n'].
  - simpl. reflexivity.
  - rewrite <- IHn'. simpl. reflexivity.
Qed.

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
         | S _ , O    => n
         | 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
          end.

        (* Can't match on multiple values with pair patterns: *)
        Definition bad_minus (n m : nat) : nat :=
          match n, m with
          | (O   , _   ) => O
          | (S _ , O   ) => n
          | (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.
  destruct p as [n m].
  simpl. reflexivity.
Qed.
(** [] *)

(** **** Exercise: 1 star, standard, optional (fst_swap_is_snd)  *)
Theorem fst_swap_is_snd : forall (p : natprod),
  fst (swap_pair p) = snd p.
Proof.
  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
             | O => 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 oddmembers (l:natlist) : natlist :=
  match l with
  | nil => nil
  | h :: t => match oddb h with
             | true => h :: (oddmembers t)
             | _ => oddmembers t
             end
  end.

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

Definition countoddmembers (l:natlist) : nat :=
  length (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, l2 with
  | nil, nil => nil
  | l,   nil => l
  | nil, l   => l
  | h1 :: t1, h2 :: t2 => h1 :: (h2 :: (alternate t1 t2))
  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
  | nil => O
  | h :: t => match eqb v h with
             | true => S (count v t)
             | _    => 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.

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

Definition add (v:nat) (s:bag) : bag := v :: s.

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 := ltb O (count v s).

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: 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
  | nil => nil
  | h :: t => match eqb v h with
             | true => t
             | _    => 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.

Fixpoint remove_all (v:nat) (s:bag) : bag :=
  match s with
  | nil => nil
  | h :: t => match eqb v h with
             | true => remove_all v t
             | _    => h :: (remove_all v t)
             end
  end.

Example test_remove_all1:  count 5 (remove_all 5 [2;1;5;4;1]) = 0.
Proof. reflexivity. Qed.
Example test_remove_all2:  count 5 (remove_all 5 [2;1;4;1]) = 0.
Proof. reflexivity. Qed.
Example test_remove_all3:  count 4 (remove_all 5 [2;1;4;5;1;4]) = 2.
Proof. reflexivity. Qed.
Example test_remove_all4:  count 5 (remove_all 5 [2;1;5;4;5;1;4;5;1;4]) = 0.
Proof. reflexivity. Qed.

Fixpoint subset (s1:bag) (s2:bag) : bool :=
  match s1 with
  | nil => true
  | h :: t => match count h s2 with
             | 0 => false
             | _ => subset t (remove_one h s2)
             end
  end.

Example test_subset1:              subset [1;2] [2;1;4;1] = true.
Proof. reflexivity. Qed.
Example test_subset2:              subset [1;2;2] [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! *)

Theorem bag_theorem : forall s : bag, forall n : nat,
    count n (add n s) = S (count n s).
Proof.
  intros s n.
  simpl. rewrite -> beq_nat_refl. 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'].
  - (* 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 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 [++].

    - 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. [] *)

(** _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, 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.
    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]: *)

(*  Search 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.
  induction l as [|h t].
  - reflexivity.
  - simpl. rewrite -> IHt. reflexivity.
Qed.

Theorem rev_app_distr: forall l1 l2 : natlist,
  rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof.
  intros l1 l2. induction l1 as [|h1 t1].
  - simpl. rewrite -> app_nil_r. reflexivity.
  - simpl. rewrite -> IHt1. rewrite -> app_assoc. reflexivity.
Qed.

Theorem rev_involutive : forall l : natlist,
  rev (rev l) = l.
Proof.
  induction l as [|h t].
  - simpl. reflexivity.
  - simpl. rewrite -> rev_app_distr. rewrite -> IHt.
    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.
  rewrite -> app_assoc. rewrite -> app_assoc.
  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 as [|h1 t1].
  - simpl. reflexivity.
  - simpl. destruct h1 as [|h1'].
    + rewrite <- IHt1. reflexivity.
    + simpl. rewrite <- IHt1. 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, l2 with
  | nil, nil => true
  | nil, _   => false
  | _,   nil => false
  | h1::t1, h2::t2 => match eqb h1 h2 with
                     | true => eqblist t1 t2
                     | _    => false
                     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.
  induction l as [|h t].
  - reflexivity.
  - simpl. rewrite -> beq_nat_refl. rewrite <- IHt. 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. 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)  *)
Theorem remove_does_not_increase_count: forall (s : bag),
  (count 0 (remove_one 0 s)) <=? (count 0 s) = true.
Proof.
  induction s as [|h t].
  - simpl. reflexivity.
  - simpl. destruct h as [|h'].
    + simpl. rewrite -> leb_n_Sn. reflexivity.
    + simpl. rewrite -> IHt. reflexivity.
Qed.
(** [] *)

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

    Write down an interesting theorem [bag_count_sum] about bags
    involving the functions [count] and [sum], and prove it using
    Coq.  (You may find that the difficulty of the proof depends on
    how you defined [count]!) *)
Theorem bag_count_sum : forall v : nat, forall (s1 s2 : bag),
    (count v s1) + (count v s2) = count v (sum s1 s2).
Proof.
  intros v s1 s2. induction s1 as [|h1 t1]. destruct s2 as [|h2 t2].
  - simpl. reflexivity.
  - simpl. destruct (v =? h2).
    + reflexivity.
    + reflexivity.
  - simpl. destruct (v =? h1).
    + simpl. rewrite -> IHt1. reflexivity.
    + rewrite -> IHt1. reflexivity.
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.) *)

Theorem rev_injective : forall (l1 l2 : natlist),
    rev l1 = rev l2 -> l1 = l2.
Proof.
  intros l1 l2 H.
  destruct l1 as [|h1 t1]. destruct l2 as [|h2 t2].
  - reflexivity.
  - rewrite <- rev_involutive. rewrite <- H. simpl. reflexivity.
  - rewrite <- rev_involutive. rewrite <- H. rewrite -> rev_involutive.
    reflexivity.
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::_ => 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.
(** [] *)

(** **** Exercise: 1 star, standard, optional (option_elim_hd)

    This exercise relates your new [hd_error] to the old [hd]. *)

Theorem option_elim_hd : forall (l:natlist) (default:nat),
  hd default l = option_elim default (hd_error l).
Proof.
  intros l default. destruct l as [|h t].
  - simpl. reflexivity.
  - simpl. 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.
  destruct x as [n].
  simpl. rewrite -> beq_nat_refl. 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 d x v. destruct d as [|x' v' d'].
  - simpl. rewrite <- eqb_id_refl. reflexivity.
  - simpl. rewrite <- eqb_id_refl. 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 d x y o H.
  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.) *)

(* The type [baz] has no element, because there is no base baz constructor *)

(* 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 *)


Set Warnings "-notation-overridden,-parsing".
From LF Require Export ProofObjects.

(** * Basics *)
(*当用inductive定义数据类型时，Coq会自动为该类型生成'归纳法则'，如果t是归纳定义的，
那么对应的归纳法则被称作t_ind*)

Check nat_ind.
(*  ===> nat_ind :
           forall P : nat -> Prop,
              P 0  ->
              (forall n : nat, P n -> P (S n))  ->
              forall n : nat, P n  *)
(*证明P n 对所有的n都成立，一个充分条件时证明，P 0成立;对任意n,若P n成立，那么P (S n)成立*)

Theorem mult_0_r' : forall n:nat,
  n * 0 = 0.
Proof.
  apply nat_ind.
  -  reflexivity.
  -  simpl. intros n' IHn'. rewrite -> IHn'.
    reflexivity.  Qed.

(** **** Exercise: 2 stars, standard, optional (plus_one_r')

    Complete this proof without using the [induction] tactic. *)

Theorem plus_one_r' : forall n:nat,
  n + 1 = S n.
Proof.
  apply nat_ind.
  - reflexivity.
  - intros n' IHn'. rewrite<-IHn'.  rewrite plus_comm. simpl.
    reflexivity.
Qed.
(** [] *)

Inductive yesno : Type :=
  | yes
  | no.

Check yesno_ind.
(* ===> yesno_ind : forall P : yesno -> Prop,
                      P yes  ->
                      P no  ->
                      forall y : yesno, P y *)

(** **** Exercise: 1 star, standard, optional (rgb) *)

Inductive rgb : Type :=
  | red
  | green
  | blue.
Check rgb_ind.
(* ===> rgb_ind : forall P : rgb -> Prop,
                  P red ->
                  P green ->
                  P blue ->
                  forall y:rgb, P y*)
(** [] *)

Inductive natlist : Type :=
  | nnil
  | ncons (n : nat) (l : natlist).

Check natlist_ind.
(* ===> (modulo a little variable renaming)
   natlist_ind :
      forall P : natlist -> Prop,
         P nnil  ->
         (forall (n : nat) (l : natlist),
            P l -> P (ncons n l)) ->
         forall n : natlist, P n *)

(** **** Exercise: 1 star, standard, optional (natlist1)

    Suppose we had written the above definition a little
   differently: *)

Inductive natlist1 : Type :=
  | nnil1
  | nsnoc1 (l : natlist1) (n : nat).

Check natlist1_ind.
(** Now what will the induction principle look like?
  natlist1_ind:
    forall P: natlist1 -> Prop,
      P nnil ->
      (forall (l:natlist1)
        P l -> forall n: nat,P (nsnocl l n)) ->
      forall n : natlist1, P n
[] *)

(** **** Exercise: 1 star, standard, optional (byntree_ind)  *)
Inductive byntree : Type :=
 | bempty
 | bleaf (yn : yesno)
 | nbranch (yn : yesno) (t1 t2 : byntree).
Check byntree_ind.
(**
  byntree_ind:
    forall P: byntree -> Prop,
      P bempty ->
      (forall (yn: yesno), P(bleaf yn)) ->
      (forall (yn: yesno), (t1: byntree),
       P t1 -> forall Pt2 -> P(nbranch yn t1 t2))->
      forall b: byntree P b
[] *)

(** **** Exercise: 1 star, standard, optional (ex_set)  *)
(*
    Here is an induction principle for an inductively defined
    set.

      ExSet_ind :
         forall P : ExSet -> Prop,
             (forall b : bool, P (con1 b)) ->
             (forall (n : nat) (e : ExSet), P e -> P (con2 n e)) ->
             forall e : ExSet, P e

    Give an [Inductive] definition of [ExSet]: *)
Inductive ExSet : Type :=
  |conl (b:bool)
  |con2 (n:nat) (e:ExSet).
(** [] *)

(* ################################################################# *)
(** * Polymorphism *)
Inductive list (X:Type) : Type :=
  |nil: list X
  |cons: X-> list X -> list X.

Inductive tree (X:Type) : Type :=
  | leaf (x : X)
  | node (t1 t2 : tree X).
Check tree_ind.
(** [] *)

(** **** Exercise: 1 star, standard, optional (mytype)

    Find an inductive definition that gives rise to the
    following induction principle:

      mytype_ind :
        forall (X : Type) (P : mytype X -> Prop),
            (forall x : X, P (constr1 X x)) ->
            (forall n : nat, P (constr2 X n)) ->
            (forall m : mytype X, P m ->
               forall n : nat, P (constr3 X m n)) ->
            forall m : mytype X, P m
*)
Inductive mytype (X:Type) : Type :=
  |constr1 (x: X)
  |constr2 (n:nat)
  |constr3 (m: mytype X) (n:nat).
Check mytype_ind.
(** [] *)

(** **** Exercise: 1 star, standard, optional (foo)

    Find an inductive definition that gives rise to the
    following induction principle:

      foo_ind :
        forall (X Y : Type) (P : foo X Y -> Prop),
             (forall x : X, P (bar X Y x)) ->
             (forall y : Y, P (baz X Y y)) ->
             (forall f1 : nat -> foo X Y,
               (forall n : nat, P (f1 n)) -> P (quux X Y f1)) ->
             forall f2 : foo X Y, P f2
*)
(** [] *)

(** **** Exercise: 1 star, standard, optional (foo')

    Consider the following inductive definition: *)

Inductive foo' (X:Type) : Type :=
  | C1 (l : list X) (f : foo' X)
  | C2.
Check foo'_ind.
(** What induction principle will Coq generate for [foo']?  Fill
   in the blanks, then check your answer with Coq.)

     foo'_ind :
        forall (X : Type) (P : foo' X -> Prop),
              (forall (l : list X) (f : foo' X),
                    P f->
                    P( C1 l f) ) ->
             foo' C2 ->
             forall f : foo' X,  P f.
*)

(** [] *)

(* ################################################################# *)
(** * Induction Hypotheses *)

(** Where does the phrase "induction hypothesis" fit into this story?*)

Definition P_m0r (n:nat) : Prop :=
  n * 0 = 0.

(** ... or equivalently: *)

Definition P_m0r' : nat->Prop :=
  fun n => n * 0 = 0.

(** Now it is easier to see where [P_m0r] appears in the proof. *)

Theorem mult_0_r'' : forall n:nat,
  P_m0r n.
Proof.
  apply nat_ind.
  - reflexivity.
  - intros n IHn.
    unfold P_m0r in IHn. unfold P_m0r. simpl. apply IHn. Qed.

Theorem plus_assoc' : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof.
  intros n m p.
  induction n as [| n'].
  - reflexivity.
  - simpl. rewrite -> IHn'. reflexivity.  Qed.

Theorem plus_comm' : forall n m : nat,
  n + m = m + n.
Proof.
  induction n as [| n'].
  - intros m. rewrite <- plus_n_O. reflexivity.
  - intros m. simpl. rewrite -> IHn'.
    rewrite <- plus_n_Sm. reflexivity.  Qed.

Theorem plus_comm'' : forall n m : nat,
  n + m = m + n.
Proof.
  induction m as [| m'].
  - simpl. rewrite <- plus_n_O. reflexivity.
  - simpl. rewrite <- IHm'.
    rewrite <- plus_n_Sm. reflexivity.  Qed.

(** **** Exercise: 1 star, standard, optional (plus_explicit_prop) *)
Theorem plus_assoc'' : forall n m o : nat,
  n+(m+o)=(n+m)+o.
Proof.
  intros.
  induction n as [| n'].
  -rewrite plus_O_n. rewrite plus_O_n. reflexivity.
  -simpl. rewrite IHn'. reflexivity.
Qed.

(* ################################################################# *)
(** * Induction Principles in [Prop] *)

Check even_ind.

Theorem ev_ev' : forall n, even n -> even' n.
Proof.
  apply even_ind.
  - apply even'_0.
  - intros m Hm IH.
    apply (even'_sum 2 m).
    + apply even'_2.
    + apply IH.
Qed.
Inductive le1 :nat-> nat -> Prop :=
  |le1_n (n:nat): le1 n n
  |le1_S (n m:nat)(H: le1 n m): le1 n (S m).
(*观察可以发现，两个构造子中左侧的参数n始终是相同的，于是可将其整体定义为一个
"一般参数",于是有如下的定义*)

Inductive le (n:nat) : nat -> Prop :=
  | le_n : le n n
  | le_S m (H : le n m) : le n (S m).

Notation "m <= n" := (le m n).
Check le_ind.
(* ===>  forall (n : nat) (P : nat -> Prop),
           P n ->
           (forall m : nat, n <= m -> P m -> P (S m)) ->
           forall n0 : nat, n <= n0 -> P n0 *)

(* ################################################################# *)
(** * Formal vs. Informal Proofs by Induction *)
Check nat_ind.
Print nat_ind.
Lemma evenb_ev : forall (n:nat),
  evenb n= true -> even n.
Proof.
  induction n; intros.
  - apply ev_0.
  - destruct n.
    +simpl in H. inversion H.
    +simpl in H. apply ev_SS.
Abort.
(*在上边关于自然数的归纳证明中，步长为1，然而我们并不能用even S n' 推出even n'
故我们需要修改自然数的归纳法则，将步长修改为2*)
Definition nat_ind2:forall (P :nat-> Prop),
  P 0 ->
  P 1 ->
  (forall (n:nat), P n-> P(S(S n))) ->
  forall n:nat, P n:=
     fun P => fun P0 => fun P1 => fun PSS =>
      fix f (n:nat) :=match n with
        |0 =>P0
        |1 => P1
        |S (S n') => PSS n' (f n')
         end.
Lemma evenb_ev: forall (n:nat), evenb n =true -> even n.
Proof.
  intros.
  induction n as [| | n'] using nat_ind2.
  -apply ev_0.
  -simpl in H. inversion H.
  -simpl in H.
    apply ev_SS.
    apply IHn'.
    apply H.
Qed.


Require Export P07.

(** The postcondition does not hold at the beginning of the loop,
    since [m = parity m] does not hold for an arbitrary [m], so we
    cannot use that as an invariant.  To find an invariant that works,
    let's think a bit about what this loop does.  On each iteration it
    decrements [X] by [2], which preserves the parity of [X].  So the
    parity of [X] does not change, i.e. it is invariant.  The initial
    value of [X] is [m], so the parity of [X] is always equal to the
    parity of [m]. Using [parity X = parity m] as an invariant we
    obtain the following decorated program:
    {{ X = m }} ->>                              (a - OK)
    {{ parity X = parity m }}
  WHILE 2 <= X DO
      {{ parity X = parity m /\ 2 <= X }}  ->>    (c - OK)
      {{ parity (X-2) = parity m }}
    X ::= X - 2
      {{ parity X = parity m }}
  END
    {{ parity X = parity m /\ X < 2 }}  ->>       (b - OK)
    {{ X = parity m }}

    With this invariant, conditions (a), (b), and (c) are all
    satisfied. For verifying (b), we observe that, when [X < 2], we
    have [parity X = X] (we can easily see this in the definition of
    [parity]).  For verifying (c), we observe that, when [2 <= X], we
    have [parity X = parity (X-2)]. *)

(** **** Exercise: 3 stars, optional (parity_formal)  *)
(** Translate this proof to Coq. Refer to the reduce-to-zero example
    for ideas. You may find the following two lemmas useful: *)

Lemma parity_ge_2 : forall x,
  2 <= x ->
  parity (x - 2) = parity x.
Proof.
  induction x; intro. reflexivity.
  destruct x. inversion H. inversion H1.
  simpl. rewrite <- minus_n_O. reflexivity.
Qed.

Lemma parity_ge_2_big : forall x,
  parity x = parity (x + 2).
intros.
  destruct x. reflexivity.
  destruct x. reflexivity.
  replace (S (S x)) with (S (S x) + 2 - 2).
  replace (S (S x) + 2 - 2 + 2) with (S (S x) + 2).
  apply parity_ge_2. omega. omega. omega. Qed.

Lemma parity_lt_2 : forall x,
  ~ 2 <= x ->
  parity (x) = x.
Proof.
  intros. induction x. reflexivity. destruct x. reflexivity.
    apply ex_falso_quodlibet. apply H. omega.
Qed.

Theorem parity_correct : forall m,
    {{ fun st => st X = m }}
  WHILE BLe (ANum 2) (AId X) DO
    X ::= AMinus (AId X) (ANum 2)
  END
    {{ fun st => st X = parity m }}.
Proof.
  intros m.
  apply hoare_consequence_pre with (P':= (fun st => (parity (st X) = parity m))).
  Case "{{I}} while {{Q}}".
    eapply hoare_consequence_post. apply hoare_while.
    SCase "{{I /\ b}} c {{I}}".
      unfold hoare_triple. intros.
      assert (Hle : 2 <= st X).
        destruct H0.
        simpl in H1. destruct (st X) eqn:Hx. inversion H1.
        destruct n eqn:Hn. inversion H1. omega.
      inversion H; subst. simpl. unfold update.
      rewrite eq_id. rewrite parity_ge_2. apply H0. assumption.

    SCase "I/\~b ->> Q".
      unfold hoare_triple, assert_implies. intros.
      destruct H. rewrite<-H. symmetry.
      apply parity_lt_2.
      unfold not. intros.
      simpl in H0. destruct (st X). inversion H1.
      destruct n. inversion H1. inversion H3.
      inversion H0.
  Case "P ->> I".
    unfold assert_implies. intros. rewrite H. omega.
Qed.


(** * Proposições definidas indutivamente *)

Set Warnings "-notation-overridden,-parsing".
Require Export aula09_logica.
Require Coq.omega.Omega.

(* ############################################### *)
(** * Proposições definidas indutivamente *)

(** Veremos agora que também é possível definir
    proposições de forma indutiva (i.e.,
    usando [Indutive].

    Por exemplo, podemos dizer que [n] é par
    escrevendo [evenb n = true] ou
    [exists k, n = double k]. Outra possibilidade
    é dizer que [n] é par se este fato pode ser
    deduzido a partir das seguintes regras:

    - Regra [ev_0]: o número [0] é par;
    - Regra [ev_SS]: se [n] é par,
                     então [S (S n)] é par.

    Para provar, por exemplo, que [4] é par, pela
    regra [ev_SS], é suficiente provar que [2] é par.
    De novo pela mesma regra, é suficente provar
    que [0] é par. Por sua vez, a regra [ev_0]
    garante que 0 é par.

    Estas regras são vistas como regras de inferência.

        ------------                        (ev_0)
           ev 0

            ev n
       --------------                      (ev_SS)
        ev (S (S n))

    Se as premissas da regra foram satisfeitas
    (listadas acima da linha), podemos concluir
    a afirmação listada abaixo da linha.

    A prova que [4] é par poderia ser escrita
    da seguinte forma:

               ------  (ev_0)
                ev 0
               ------ (ev_SS)
                ev 2
               ------ (ev_SS)
                ev 4

    Em Coq, podemos, então, definir a propriedade
    de ser par da seguinte forma indutiva. Cada
    construtor corresponde a uma regra de inferência. *)

Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall n : nat, ev n -> ev (S (S n)).

Check ev_0.
Check ev.
Check ev_SS.

(** Observe que esta definição não resulta em um
    [Type], mas uma função de [nat] para [Prop];
    ou seja, uma propriedade sobre números.

    Além disto, observe que na definição de ev
    (linha 58), o argumento natural aparece sem
    nome (i.e., à direita do [:]). Na definição
    de listas, por exemplo, temos:

    Inductive list (X:Type) : Type :=

    Observe que aqui o X aparece antes do [: Type].
    Isto permite [ev] receber valores diferentes
    nos diferentes construtores. Veja que a
    definição abaixo gera um erro. *)

Fail Inductive wrong_ev (n : nat) : Prop :=
| wrong_ev_0 : wrong_ev 0
| wrong_ev_SS : forall n, wrong_ev n -> wrong_ev (S (S n)).
(* ===> Error: A parameter of an inductive type n is not
        allowed to be used as a bound variable in the type
        of its constructor. *)

(** Podemos, portanto, pensar na definição de [ev]
    como a função [ev : nat -> Prop], em conjunto
    com os teoremas primitivos [ev_0 : ev 0] e
    [ev_SS : forall n, ev n -> ev (S (S n))].

    Tais "teoremas-construtores" possuem o mesmo
    status de outros teoremas em Coq. Em particular,
    podemos usar [apply] com o nome destes
    "teoremas-construtores". *)

Theorem ev_4 : ev 4.
Proof. apply ev_SS. apply ev_SS. apply ev_0. Qed.

(** ... ou ainda por uma perspectiva funcional. *)

Print ev_SS.
Compute (ev_SS).
Compute (ev_SS 0 ev_0).

Theorem ev_4' : ev 4.
Proof.
  Compute (ev_SS 2 (ev_SS 0 ev_0)).
  apply (ev_SS 2 (ev_SS 0 ev_0)).
Qed.

(** Outro exemplo. *)

Theorem ev_plus4 :
  forall n, ev n -> ev (4 + n).
Proof.
  intros n. simpl. intros Hn.
  apply ev_SS. apply ev_SS. apply Hn.
Qed.

(** **** Exercise: (ev_double)  *)
Theorem ev_double :
  forall n, ev (double n).
Proof.
  intros n. induction n as [|n'].
  - simpl. apply ev_0.
  - simpl. apply ev_SS. apply IHn'.
Qed.

(* ############################################### *)
(** * Usando evidência em provas *)

(** Definir [ev] como uma declaração [Inductive],
    não só diz que [ev_0] e [ev_SS] são formas
    válidas de criar evidência sobre números
    serem pares, mas também que estes dois
    construtores são as _únicas_ formas de criar
    evidência que números são pares (no contexto,
    da definição de [ev]).

    Logo, se tivermos uma evidência que [E]
    para a afirmação [ev n], [E] precisa ter uma
    das seguintes formas:

    - [E] é [ev_0] (e [n] é [O]), ou
    - [E] é [ev_SS n' E'] (e [n] é [S (S n')],
      onde [E'] é a evidência para [ev n']).

    Portanto, é possível usar táticas como [inversion],
    [induction] e [destruct] em evidências criadas
    indutivamente. *)

(** ** Inversion em evidências *)

(** Neste contexto, [inversion] realiza uma análise
    de casos, e sua sintaxe é similar à do
    [destruct]. Veja o exemplo abaixo. *)

Theorem ev_minus2 : forall n,
  ev n -> ev (pred (pred n)).
Proof.
  intros n E.
  inversion E as [| n' E'].
  - (* E = ev_0 *) simpl. apply ev_0.
  - (* E = ev_SS n' E' *) simpl. apply E'.
Qed.

(** Neste caso, poderíamos ter usado [destruct]. *)

Theorem ev_minus2' : forall n,
  ev n -> ev (pred (pred n)).
Proof.
  intros n E.
  destruct E as [| n' E'].
  - (* E = ev_0 *) simpl. apply ev_0.
  - (* E = ev_SS n' E' *) simpl. apply E'.
Qed.

(** Nem sempre o uso de [inversion] e
    [destruct] produz o mesmo resultado. *)

Theorem evSS_ev : forall n,
  ev (S (S n)) -> ev n.
Proof.
  intros n E.

(** Como aqui temos o [ev] aplicado a um
    elemento diferente de 0, esta evidência
    precisa ter sido construída a partir de
    ev_SS. No entanto, a tática [destruct]
    não faz este tipo de análise, e gera
    dois objetivos de prova. *)
  destruct E as [| n' E'].
  - (* E = ev_0. *)
    (* Não é possível provar que [n] é par a partir
       de nenhuma premissa. *)
Abort.

(** Veja a prova com [inversion]. A tática [inversion]
    detectou que (1) o caso ev_0 não se aplica, pois
    0 não pode ser igual a [S (S n)] e que (2) em
    [ev_SS n' E'], E = ev n' = ev n, pois n = n',
    uma vez que [S (S n')] = [S (S n)]. *)

Theorem evSS_ev : forall n,
  ev (S (S n)) -> ev n.
Proof.
  intros n E.
  inversion E as [| n' E'].
  (* Caso que [E = ev_SS n' E']. *)
  apply E'.
Qed.

(** Também podemos usar [inversion] como
    princípio da explicação em hipóteses
    envolvendo propriedades indutivas
    que são claramente contradições. *)

Theorem one_not_even : ~ ev 1.
Proof.
  unfold not. intros H. inversion H.
Qed.

(** **** Exercise: (SSSSev__even)  *)
(** Prove o seguinte resultado usando [inversion]. *)

Theorem SSSSev__even : forall n,
  ev (S (S (S (S n)))) -> ev n.
Proof.
  intros n E. inversion E as [| n' E'].
  inversion E' as [| n'' E''].
  apply E''.
Qed.

(** **** Exercise: (even5_nonsense)  *)
(** Prove o seguinte resultado usando [inversion]. *)

Theorem even5_nonsense :
  ev 5 -> 2 + 2 = 9.
Proof.
  intros E. inversion E. inversion H0. inversion H2.
Qed.

(** ** Indução sobre evidências *)

(** Veja o exemplo a seguir. *)

Lemma ev_even : forall n,
  ev n -> exists k, n = double k.
Proof.
  intros n E.
  induction E as [|n' E' IH].
  - (* E = ev_0 *)
    exists 0. reflexivity.
  - (* E = ev_SS n' E'
       com IH : exists k', n' = double k' *)
    destruct IH as [k' Hk'].
    rewrite Hk'. exists (S k').
    simpl. reflexivity.
Qed.

(** Com este resultado, podemos provar
    que a propriedade de ser par definida
    por [ev n] e [exists k, n = double k]
    são equivalentes. *)

Theorem ev_even_iff : forall n,
  ev n <-> exists k, n = double k.
Proof.
  intros n. split.
  - (* -> *) apply ev_even.
  - (* <- *) intros [k Hk].
             rewrite Hk. apply ev_double.
Qed.

(** **** Exercise: (ev_sum)  *)
Theorem ev_sum :
  forall n m, ev n -> ev m -> ev (n + m).
Proof.
  intros n m.
  intros En Em.
  Print Nat.add.
  induction En as [| n' En' IHn].
  - simpl. apply Em.
  - simpl. apply ev_SS. apply IHn.
Qed.

(** **** Exercise: (ev_ev__ev)  *)
Theorem ev_ev__ev : forall n m,
  ev (n+m) -> ev n -> ev m.
Proof.
  intros n m. intros Enm En. induction En as [| n' En' IHn].
  - simpl in Enm. apply Enm.
    (** Search (_ + _ = 0 -> _ = 0 /\ _ = 0).
    symmetry in H0. apply Plus.plus_is_O in H0.
    apply proj2 in H0. rewrite H0. apply ev_0.
    **)
  - simpl in Enm. inversion Enm. apply IHn in H0.
    apply H0.
Qed.

(* ############################################### *)
(** * Relações indutivas *)

(** Uma proposição parametrizada por um número
    (como [ev]), pode ser vista como uma propriedade
    sobre números: define um subconjunto de [nat]
    para os quais a propriedade pode ser provada.

    De forma similar, uma proposição com dois
    argumentos pode ser vista como uma relação:
    define um conjunto de pares para os quais
    a propriedade em questão pode ser provada. *)

Module Playground.

(** A próxima definição afirma que existem duas
    maneiras de produzir evidência de que um número
    é <= a outro: ou estes números são os mesmos,
    ou então o primeiro é <= ao predecessor
    do primeiro. *)

Inductive le : nat -> nat -> Prop :=
  | le_n : forall n, le n n
  | le_S : forall n m, (le n m) -> (le n (S m)).

Notation "m <= n" := (le m n).

(** A seguir, alguns testes para demonstrar
    que a definição de [le] é correta. Aqui,
    não é suficiente usar [simpl] e [reflexivity],
    uma vez que a prova não consiste em simplificar
    computações. *)

Theorem test_le1 :
  3 <= 3.
Proof.
  apply le_n.
Qed.

Theorem test_le2 :
  3 <= 6.
Proof.
  apply le_S. apply le_S.
  apply le_S. apply le_n.
Qed.

Theorem test_le3 :
  (2 <= 1) -> 2 + 2 = 5.
Proof.
  intros H. inversion H.
  inversion H2.
Qed.

(** O operador [<] pode ser definido
    em termos de [le]. *)

End Playground.

Print le.

Definition lt (n m:nat) := le (S n) m.

Notation "m < n" := (lt m n).

(** Outros exemplos de relações sobre números. *)

Inductive square_of : nat -> nat -> Prop :=
  | sq : forall n:nat, square_of n (n * n).

Inductive next_nat : nat -> nat -> Prop :=
  | nn : forall n:nat, next_nat n (S n).

Inductive next_even : nat -> nat -> Prop :=
  | ne_1 : forall n, ev (S n) -> next_even n (S n)
  | ne_2 : forall n, ev (S (S n)) -> next_even n (S (S n)).

(** **** Exercise: (le_exercises)  *)
(** A seguir, vários exercícios sobre as relações
    [<=] e [<], que constituem uma boa prática. *)

Lemma le_Sm_n :
  forall m n, S m <= n -> m <= n.
Proof.
  intros m n H. induction H as [|m' H IHm'].
  - apply le_S. apply le_n.
  - apply le_S. apply IHm'.
Qed.

Lemma le_trans :
  forall m n o, m <= n -> n <= o -> m <= o.
Proof.
  intros m n o H. induction H as [| m' H IHm'].
  - intros H1. apply H1.
  - intros H2. apply le_Sm_n in H2. apply IHm'. apply H2.
Qed.

Theorem O_le_n : forall n,
  0 <= n.
Proof.
  induction n as [| n' IH'].
  - apply le_n.
  - apply le_S. apply IH'.
Qed.

Theorem n_le_m__Sn_le_Sm : forall n m,
  n <= m -> S n <= S m.
Proof.
  intros n m le_n_m. induction le_n_m.
  - apply le_n.
  - apply le_S. apply IHle_n_m.
Qed.

Theorem Sn_le_Sm__n_le_m : forall n m,
  S n <= S m -> n <= m.
Proof.
  intros n m. intros H. inversion H.
  - apply le_n.
  - apply le_Sm_n in H1. apply H1.
Qed.

Theorem le_plus_l : forall a b,
  a <= a + b.
Proof.
  intros a b. induction a as [| a' IHa'].
  - simpl. apply O_le_n.
  - simpl. apply n_le_m__Sn_le_Sm. apply IHa'.
Qed.

Theorem plus_lt : forall n1 n2 m,
  n1 + n2 < m -> n1 < m /\ n2 < m.
Proof.
  intros n1 n2 m. intros H. induction H.
  - unfold lt. split.
    + apply n_le_m__Sn_le_Sm. apply le_plus_l.
    + apply n_le_m__Sn_le_Sm. rewrite plus_comm.
      apply le_plus_l.
  - split.
    + apply proj1 in IHle. unfold lt.
      unfold lt in IHle. apply le_S. apply IHle.
    + apply proj2 in IHle. unfold lt.
      unfold lt in IHle. apply le_S. apply IHle.
Qed.

Theorem lt_S : forall n m,
  n < m -> n < S m.
Proof.
  intros n m. unfold lt. intros H.
  apply le_S. apply H.
Qed.

Theorem leb_complete : forall n m,
  leb n m = true -> n <= m.
Proof.
  intros n. induction n as [| n' IHn'].
  - simpl. intros m. intros H. apply O_le_n.
  - simpl. intros m. intros H. destruct m as [|m'].
    + inversion H.
    + apply IHn' in H. apply n_le_m__Sn_le_Sm. apply H.
Qed.

(** O próximo teorema é mais fácil de provar
    com uma indução sobre [m]. *)

Theorem leb_correct : forall n m,
  n <= m ->
  leb n m = true.
Proof.
  intros n m. generalize dependent n.
  induction m as [| m' IHm'].
  - intros n. intros H. inversion H.
    reflexivity.
  - intros n. intros H. destruct n as [| n'].
    + simpl. reflexivity.
    + simpl. apply Sn_le_Sm__n_le_m in H.
      apply IHm' in H. apply H.
Qed.

(** O próximo teorema pode ser provado
    facilmente sem [induction]. *)

Theorem leb_true_trans : forall n m o,
  leb n m = true ->
  leb m o = true -> leb n o = true.
Proof.
  intros n m o. intros Hnm Hmo.
  apply leb_complete in Hnm.
  apply leb_complete in Hmo.
  Search "le_trans".
  apply leb_correct.
  apply le_trans with (n := m).
  - apply Hnm.
  - apply Hmo.
Qed.

(* ############################################### *)
(** * Estudo de caso: expressões regulares *)

(** Primeiro, a sintaxe. *)

Inductive reg_exp {T : Type} : Type :=
| EmptySet  : reg_exp
| EmptyStr  : reg_exp
| Char      : T -> reg_exp
| App       : reg_exp -> reg_exp -> reg_exp
| Union     : reg_exp -> reg_exp -> reg_exp
| Star      : reg_exp -> reg_exp.

(** Agora, a semântica (como uma relação indutiva). *)

Inductive exp_match {T} : list T -> reg_exp -> Prop :=
| MEmpty    : exp_match [] EmptyStr
| MChar     : forall x, exp_match [x] (Char x)
| MApp      : forall s1 re1 s2 re2,
                exp_match s1 re1 ->
                exp_match s2 re2 ->
                exp_match (s1 ++ s2) (App re1 re2)
| MUnionL   : forall s1 re1 re2,
                exp_match s1 re1 ->
                exp_match s1 (Union re1 re2)
| MUnionR   : forall re1 s2 re2,
                exp_match s2 re2 ->
                exp_match s2 (Union re1 re2)
| MStar0    : forall re, exp_match [] (Star re)
| MStarApp  : forall s1 s2 re,
                exp_match s1 re ->
                exp_match s2 (Star re) ->
                exp_match (s1 ++ s2) (Star re).

(** Açúcar sintático. *)

Notation "s =~ re" := (exp_match s re) (at level 80).

(** A relação anterior define as seguintes regras.

      ----------------                    (MEmpty)
       [] =~ EmptyStr

      ---------------                      (MChar)
       [x] =~ Char x

   s1 =~ re1    s2 =~ re2
  -------------------------                 (MApp)
   s1 ++ s2 =~ App re1 re2

          s1 =~ re1
    ---------------------                (MUnionL)
     s1 =~ Union re1 re2

          s2 =~ re2
    ---------------------                (MUnionR)
     s2 =~ Union re1 re2

      ---------------                     (MStar0)
       [] =~ Star re

  s1 =~ re    s2 =~ Star re
 ---------------------------            (MStarApp)
    s1 ++ s2 =~ Star re
*)

(** Alguns exemplos. *)

Example reg_exp_ex1 :
  [1] =~ Char 1.
Proof.
  apply MChar.
Qed.

Example reg_exp_ex2 :
  [1; 2] =~ App (Char 1) (Char 2).
Proof.
  Compute (MApp [1] _ [2] _).
  apply (MApp [1] _ [2] _).
  - apply MChar.
  - apply MChar.
Qed.

(** Observe que no caso anterior é preciso
    manualmente informar como dividir a
    string [1;2] em [1] e [2]. Se o objetivo
    fosse [1] ++ [2], Coq conseguiria inferir. *)

Example reg_exp_ex3 :
  ~ ([1; 2] =~ Char 1).
Proof.
  intros H. inversion H.
Qed.

(** Provando que toda string [s] que
    casa com o padrão [re], casa também
    com o padrão [Star re]. *)

Lemma MStar1 :
  forall T s (re : @reg_exp T) ,
    s =~ re -> s =~ Star re.
Proof.
  intros T s re H.
  rewrite <- (app_nil_r _ s).
  apply (MStarApp s [] re).
  - apply H.
  - apply MStar0.
Qed.

(* ############################################### *)
(** * Leitura sugerida *)

(** Software Foundations: volume 1
  - Inductively defined propositions
  https://softwarefoundations.cis.upenn.edu/lf-current/IndProp.html
*)


(** Exercise 1 (andb_true_elim2) *)
Theorem andb_true_elim2 : forall b c : bool,
  andb b c = true -> c = true.
Proof.
  intros b c H. destruct c.
  Case "c = true".
    reflexivity.
  Case "c = false".
    rewrite <- H. destruct b.
    SCase "b = true".
      reflexivity.
    SCase "b = false".
      reflexivity.  Qed.

(** Exercise 2 (basic_induction) *)
Theorem mult_0_r : forall n:nat,
  n * 0 = 0.
Proof.
  intros n. induction n as [| n'].
  Case "n = 0".
    reflexivity.
  Case "n = S n'".
    simpl. rewrite -> IHn'. reflexivity.  Qed.

Theorem plus_n_Sm : forall n m : nat,
  S (n + m) = n + (S m).
Proof.
  intros n m. induction n as [| n'].
  Case "n = 0".
    reflexivity.
  Case "n = S n'".
    simpl. rewrite -> IHn'. reflexivity.  Qed.

Theorem plus_comm : forall n m : nat,
  n + m = m + n.
Proof.
  intros n m. induction n as [| n'].
  Case "n = 0".
    rewrite -> plus_0_r. reflexivity.
  Case "n = S n'".
    simpl. rewrite -> IHn'. rewrite -> plus_n_Sm. reflexivity.  Qed.

Theorem plus_assoc : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof.
  intros n m p. induction n as [| n'].
  Case "n = 0".
    reflexivity.
  Case "n = S n'".
    simpl. rewrite -> IHn'. reflexivity.  Qed.

(** Exercise 3 (double_plus) *)
Fixpoint double (n:nat) :=
  match n with
  | O => O
  | S n' => S (S (double n'))
  end.

(** Use induction to prove this simple fact about [double]: *)

Lemma double_plus : forall n, double n = n + n .
Proof.
  intros n. induction n as [| n'].
  Case "n = 0".
    reflexivity.
  Case "n = S n'".
    simpl. rewrite -> IHn'. rewrite -> plus_n_Sm. reflexivity.  Qed.

(** Exercise 4 (destruct_induction) *)
(** Induction does a destruct but also adds the induction hypothesis.
      Destruct only destructurizes, but does not add any Induction hypothesis. *)

(** Exercise 5 (evenb_n__oddb_Sn) *)
Theorem evenb_n__oddb_Sn : forall n : nat,
  evenb n = negb (evenb (S n)).
Proof.
  intros n. induction n as [| n'].
  Case "n = 0".
    reflexivity.
  Case "n = S n'".
    assert (H: evenb (S (S n')) = evenb n').
    SCase "Proof of assertion".
      reflexivity.
    rewrite -> H. rewrite -> IHn'.
    rewrite -> negb_involutive. reflexivity.  Qed.

(** Exercise 6 (more_exercises) *)
Theorem ble_nat_refl : forall n:nat,
  true = ble_nat n n.
Proof.
(* prediction: need induction *)
  intros n. induction n. reflexivity. simpl. rewrite <- IHn. reflexivity. Qed.

Theorem zero_nbeq_S : forall n:nat,
  beq_nat 0 (S n) = false.
Proof.
(* prediction: do not need induction, just reflexivity *)
Proof. reflexivity. Qed.

Theorem andb_false_r : forall b : bool,
  andb b false = false.
Proof.
(* prediction: need destruct because b comes first in andb *)
Proof. intros b. destruct b. Case "b=true". reflexivity. Case "b=false". reflexivity. Qed.

Theorem plus_ble_compat_l : forall n m p : nat,
  ble_nat n m = true -> ble_nat (p + n) (p + m) = true.
Proof.
(* prediction: need induction in p, because p comes first in the goal. *)
  Proof. intros n m p. intros H.  (* note: important to introduce H before starting the induction. *)
induction p.
Case "p=0". simpl. rewrite <- H. reflexivity.
Case "S p". simpl. rewrite <- IHp. reflexivity. Qed.

Theorem S_nbeq_0 : forall n:nat,
  beq_nat (S n) 0 = false.
Proof.
(* prediction: do not need induction *)
  reflexivity. Qed.

Theorem mult_1_l : forall n:nat, 1 * n = n.
Proof.
(* prediction: do not need induction because 1 comes first in mult? Actually, we would need induction if we didn't use plus_0_r: mult is more difficult than plus to prove things about. *)
  intros n. simpl. rewrite -> plus_0_r. reflexivity. Qed.

Theorem all3_spec : forall b c : bool,
    orb
      (andb b c)
      (orb (negb b)
               (negb c))
  = true.
Proof.
(* prediction: need to destructure b since it comes first in andb.
Actually, also need to destructure c, because can't compute negb c in general.
Otherwise would have to prove many lemmas about orb x (negb x)= true etc. *)
 intros b c. destruct b.
Case "b=true". destruct c.
SCase "c=true". reflexivity.
SCase "c=false". reflexivity.
Case "b=false". destruct c.
SCase "c=true". reflexivity.
SCase "c=false". reflexivity. Qed.

Theorem mult_plus_distr_r : forall n m p : nat,
(* prediction: need induction in n because it comes first in goals. *)

  (n + m) * p = (n * p) + (m * p).
Proof. intros n m p.
induction n. Case "n=0". reflexivity.
Case "S n". simpl. rewrite <- plus_assoc. rewrite <- IHn. reflexivity. Qed.

Theorem mult_assoc : forall n m p : nat,
  n * (m * p) = (n * m) * p.
(* prediction: do not need induction, just rewriting.
This is wrong: we don't have any rewriting rules for this yet, only for plus with mult.
So we have to use induction in n, at least. *)
Proof.
  intros n m p. induction n.
Case "n=0". reflexivity.
Case "S n".  simpl. rewrite -> mult_plus_distr_r. rewrite -> IHn. reflexivity. Qed.

(** Exercise 7 (beq_nat_refl) *)
Theorem beq_nat_refl : forall n : nat,
  true = beq_nat n n.
Proof.
(* prediction: need induction in n *)

intros n. induction n. Case "n=0". reflexivity.
Case "S n". simpl. rewrite <- IHn. reflexivity. Qed.

(** Exercise 8 (plus_swap') *)
Theorem plus_swap' : forall n m p : nat,
  n + (m + p) = m + (n + p).
Proof.
 intros n m p. rewrite -> plus_comm. replace (n+p) with (p+n).
rewrite <- plus_assoc. reflexivity.
Case "p+n=n+p". rewrite -> plus_comm. reflexivity. Qed.


(** * Multiset:  Insertion Sort Verified With Multisets *)

(** Our specification of [sorted] in [Sort] was based in
    part on permutations, which enabled us to express the idea that
    sorting rearranges list elements but does not add or remove any.

    Another way to express that idea is to use multisets, aka bags.  A
    _set_ is like a list in which element order is irrelevant, and in
    which no duplicate elements are permitted. That is, an element can
    either be _in_ the set or not in the set, but it can't be in the
    set multiple times.  A _multiset_ relaxes that restriction: an
    element can be in the multiset multiple times.  The number of
    times the element occurs in the multiset is the element's
    _multiplicity_. *)

(** For example:

    - [{1, 2}] is a set, and is the same as set [{2, 1}].

    - [[1; 1; 2]] is a list, and is different than list [[2; 1; 1]].

    - [{1, 1, 2}] is a multiset and the same as multiset [{2, 1, 1}].

    In this chapter we'll explore using multisets to specify
    sortedness. *)

From Coq Require Import Strings.String.  (* for manual grading *)
From Coq Require Import FunctionalExtensionality.
From VFA Require Import Perm.
From VFA Require Import Sort.

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

(** We will represent multisets as functions: if [m] is a
    multiset, then [m n] will be the multiplicity of [n] in [m].
    Since we are sorting lists of natural numbers, the type of
    multisets would be [nat -> nat]. The input is the value, the output is
    its multiplicity.  To help avoid confusion between those two uses
    of [nat], we'll introduce a synonym, [value]. *)

Definition value := nat.

Definition multiset := value -> nat.

(** The [empty] multiset has multiplicity [0] for every value. *)

Definition empty : multiset :=
  fun x => 0.

(** Multiset [singleton v] contains only [v], and exactly once. *)

Definition singleton (v: value) : multiset :=
  fun x => if x =? v then 1 else 0.

(** The union of two multisets is their _pointwise_ sum. *)

Definition union (a b : multiset) : multiset :=
  fun x => a x + b x.

(** **** Exercise: 1 star, standard (union_assoc)  *)

(** Prove that multiset union is associative.

    To prove that one multiset equals another we use the axiom of
    functional extensionality, which was introduced in
    [Logic]. We begin the proof below by using Coq's tactic
    [extensionality], which applies that axiom.*)

Lemma union_assoc: forall a b c : multiset,
   union a (union b c) = union (union a b) c.
Proof.
  intros.
  extensionality x.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** **** Exercise: 1 star, standard (union_comm)  *)

(** Prove that multiset union is commutative. *)

Lemma union_comm: forall a b : multiset,
   union a b = union b a.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

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

(** Prove that the multisets in a nested union can be swapped.
    You do not need [extensionality] if you use the previous
    two lemmas. *)

Lemma union_swap : forall a b c : multiset,
    union a (union b c) = union b (union a c).
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** Note that this is not an efficient implementation of multisets.
    We wouldn't want to use it for programs with high performance
    requirements.  But we are using multisets for specifications, not
    for programs.  We don't intend to build large multisets, only to
    use them in verifying algorithms such as insertion sort.  So this
    inefficiency is not a problem. *)

(* ################################################################# *)
(** * Specification of Sorting *)

(** A sorting algorithm must rearrange the elements into a list
    that is totally ordered.  Using multisets, we can restate that as:
    the algorithm must produce a list _with the same multiset of
    values_, and this list must be totally ordered. Let's formalize
    that idea. *)

(** The _contents_ of a list are the elements it contains, without
    any notion of order. Function [contents] extracts the contents
    of a list as a multiset. *)

Fixpoint contents (al: list value) : multiset :=
  match al with
  | [] => empty
  | a :: bl => union (singleton a) (contents bl)
  end.

(** The insertion-sort program [sort] from [Sort] preserves
    the contents of a list.  Here's an example of that: *)

Example sort_pi_same_contents:
  contents (sort [3;1;4;1;5;9;2;6;5;3;5]) = contents [3;1;4;1;5;9;2;6;5;3;5].
Proof.
  extensionality x.
  repeat (destruct x; try reflexivity).
  (* Why does this work? Try it step by step, without [repeat]. *)
Qed.

(** A sorting algorithm must preserve contents and totally order the
    list. *)

Definition is_a_sorting_algorithm' (f: list nat -> list nat) := forall al,
    contents al = contents (f al) /\ sorted (f al).

(** That definition is similar to [is_a_sorting_algorithm] from [Sort],
    except that we're now using [contents] instead of [Permutation]. *)

(* ################################################################# *)
(** * Verification of Insertion Sort *)

(** The following series of exercises will take you through a
    verification of insertion sort using multisets. *)

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

(** Prove that insertion sort's [insert] function produces the same
    contents as merely prepending the inserted element to the front of
    the list.

    Proceed by induction.  You do not need [extensionality] if you
    make use of the above lemmas about [union]. *)

Lemma insert_contents: forall x l,
     contents (insert x l) = contents (x :: l).
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

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

(** Prove that insertion sort preserves contents. Proceed by
    induction.  Make use of [insert_contents]. *)

Theorem sort_contents: forall l,
    contents l = contents (sort l).
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** **** Exercise: 1 star, standard (insertion_sort_correct)  *)

(** Finish the proof of correctness! *)

Theorem insertion_sort_correct :
  is_a_sorting_algorithm' sort.
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** **** Exercise: 1 star, standard (permutations_vs_multiset)

    Compare your proofs of [insert_perm, sort_perm] with your proofs
    of [insert_contents, sort_contents].  Which proofs are simpler?

      - [ ] easier with permutations
      - [ ] easier with multisets
      - [ ] about the same

   Regardless of "difficulty", which do you prefer or find easier to
   think about?
      - [ ] permutations
      - [ ] multisets

   Put an X in one box in each list. *)

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

(** [] *)

(* ################################################################# *)
(** * Equivalence of Permutation and Multiset Specifications *)

(** We have developed two specifications of sorting, one based
    on permutations ([is_a_sorting_algorithm]) and one based on
    multisets ([is_a_sorting_algorithm']).  These two specifications
    are actually equivalent, which will be the final theorem in this
    chapter.

    One reason for that equivalence is that permutations and multisets
    are closely related.  We'll begin by proving:

        Permutation al bl <-> contents al = contents bl

    The forward direction is relatively easy, but the backward
    direction is surprisingly difficult.
 *)

(* ================================================================= *)
(** ** The Forward Direction *)

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

(** The forward direction is the easier one. Proceed by induction on
    the evidence for [Permutation al bl]: *)

Lemma perm_contents: forall al bl : list nat,
    Permutation al bl -> contents al = contents bl.
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(* ================================================================= *)
(** ** The Backward Direction (Advanced) *)

(** The backward direction is surprisingly difficult.  This proof
    approach is due to Zhong Sheng Hu.  The first three lemmas are
    used to prove the fourth one.  Don't forget that [union],
    [singleton], and [empty] must be explicitly unfolded to access
    their definitions. *)

(** **** Exercise: 2 stars, advanced (contents_nil_inv)  *)
Lemma contents_nil_inv : forall l, (forall x, 0 = contents l x) -> l = nil.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars, advanced (contents_cons_inv)  *)
Lemma contents_cons_inv : forall l x n,
    S n = contents l x ->
    exists l1 l2,
      l = l1 ++ x :: l2
      /\ contents (l1 ++ l2) x = n.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 2 stars, advanced (contents_insert_other)  *)
Lemma contents_insert_other : forall l1 l2 x y,
    y <> x -> contents (l1 ++ x :: l2) y = contents (l1 ++ l2) y.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars, advanced (contents_perm)  *)
Lemma contents_perm: forall al bl,
    contents al = contents bl -> Permutation al bl.
Proof.
  intros al bl H0.
  assert (H: forall x, contents al x = contents bl x).
  { rewrite H0. auto. }
  clear H0.
  generalize dependent bl.
(* FILL IN HERE *) Admitted.
(** [] *)

(* ================================================================= *)
(** ** The Main Theorem *)

(** With both directions proved, we can establish the correspondence
    between multisets and permutations. *)

(** **** Exercise: 1 star, standard (same_contents_iff_perm)  *)

(** Use [contents_perm] (even if you haven't proved it) and
    [perm_contents] to quickly prove the next theorem. *)

Theorem same_contents_iff_perm: forall al bl,
    contents al = contents bl <-> Permutation al bl.
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** Therefore the two specifications are equivalent. *)

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

Theorem sort_specifications_equivalent: forall sort,
    is_a_sorting_algorithm sort <-> is_a_sorting_algorithm' sort.
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** That means we can verify sorting algorithms using either
    permutations or multisets, whichever we find more convenient. *)

(* 2020-08-07 17:08 *)


(*
 * その7: https://www.fos.kuis.kyoto-u.ac.jp/~igarashi/class/cal/handout7.pdf
 * 帰納命題
 *)

Require Import Arith List Omega ZArith.
From mathcomp Require Import all_ssreflect.
Import ListNotations.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

(*
帰納型の宣言
*)
Inductive ev : nat -> Prop :=
| ev_O : ev 0
| ev_SS n (H : ev n) : ev n.+2.

Check (ev 0).
Check ev_O.  (* ev 0 *)
Check (ev_SS ev_O).  (* ev 2 *)
Check (ev_SS (ev_SS ev_O)).  (* ev 4 *)

(*
帰納構造に関する証明
*)

Theorem four_is_even : ev 4.
Proof.
  apply ev_SS.
  apply ev_SS.
  by apply ev_O.
Qed.

(*
逆転の定理
*)
Theorem ev_inversion :
  forall n, ev n -> n = 0 \/ (exists m, n = m.+2 /\ ev m).
Proof.
  intros n Hn.
  destruct Hn as [|m Hm].
  - by left.
  - right.
    exists m.
    done.
Qed.

(*
inversion タクティクス
*)
Theorem evSS_ev : forall n, ev n.+2 -> ev n.
Proof.
  intros n E.
  inversion E as [|m H1 H2].
  exact.
Qed.

Theorem evSSSS_ev : forall n, ev n.+4 -> ev n.
Proof.
  intros n E.
  inversion E as [|m H1 H2].
  inversion H1 as [|k H3 H4].
  exact.
Qed.

Theorem inversion_ex1 : forall n m o : nat, [n;m] = [o;o] -> [n] = [m].
Proof.
  intros n m o H.
  inversion H. (* works as injection *)
  done.
Qed.

Theorem inversion_ex2 : forall n : nat, n.+1 = 0 -> 2 + 2 = 5.
Proof.
  intros n H.
  inversion H.  (* works as discriminate *)
Qed.

Theorem inversion_ex_S_injective : forall n m, S n = S m -> n = m.
Proof.
  intros n m H.
  inversion H.
  exact.
Qed.

(*
  ev の構造に関する帰納法
 *)
Lemma even_is_double_of_something : forall n,
  ev n -> exists k, n = double k.
Proof.
  intros n E.
  induction E.
  - by exists 0.
  - destruct IHE.
    exists (x.+1).
    rewrite -muln2.
    rewrite mulSn.
    rewrite muln2.
    rewrite -H.
    done.
Qed.


Require Import Coq.Arith.Arith.
Require Import Coq.Lists.List.

Import ListNotations.

Fixpoint combine {X Y : Type} (lx : list X) (ly : list Y)
  : list (X*Y) :=
  match lx, ly with
  | [], _ => []
  | _, [] => []
  | x :: tx, y :: ty => (x, y) :: (combine tx ty)
  end.

Fixpoint split {X Y : Type} (l : list (X*Y)) : (list X) * (list Y) :=
  match l with
  | [] => ([],[])
  | (x,y) :: ls => let rest := split ls in (x :: fst rest, y :: snd rest)
  end.

Fixpoint filter {X : Type} (f : X -> bool) (l : list X) : list X :=
  match l with
  | [] => []
  | x :: xs => if f x then x :: filter f xs else filter f xs
  end.

Example test_split:
  split [(1,false);(2,false)] = ([1;2],[false;false]).
Proof. auto. Qed.

Definition filter_even_gt7 (l : list nat) : list nat :=
  filter (fun n => andb (NPeano.leb 7 n) (NPeano.even n)) l.

Example test_filter_even_gt7_1 :
  filter_even_gt7 [1;2;6;9;10;3;12;8] = [10;12;8].
Proof. auto. Qed.
Example test_filter_even_gt7_2 :
  filter_even_gt7 [5;2;6;19;129] = [].
Proof. auto. Qed.

Definition partition {X : Type} (test : X -> bool) (l : list X)
  : list X * list X :=
  (filter test l, filter (fun x => negb (test x)) l).

Example test_partition1: partition NPeano.odd [1;2;3;4;5] = ([1;3;5], [2;4]).
Proof. auto. Qed.
Example test_partition2: partition (fun x => false) [5;9;0] = ([], [5;9;0]).
Proof. auto. Qed.

Theorem map_rev : forall (X Y : Type) (f : X -> Y) (l : list X),
    List.map f (List.rev l) = List.rev (List.map f l).
Proof.
  induction l.
  - reflexivity.
  - simpl.
    rewrite map_app, IHl.
    reflexivity.
Qed.

Fixpoint foldr {X Y : Type} (f : X -> Y -> Y) (y : Y) (l : list X) : Y :=
  match l with
  | [] => y
  | x :: xs => f x (foldr f y xs)
  end.

Definition fold_length {X : Type} (l : list X) : nat :=
  foldr (fun _ n => S n) 0 l.

Example test_fold_length1 : fold_length [4;7;0] = 3.
Proof. auto. Qed.
Theorem fold_length_correct : forall X (l : list X),
    fold_length l = length l.
Proof.
  induction l.
  - reflexivity.
  - simpl. rewrite <- IHl.
    unfold fold_length. simpl. reflexivity.
Qed.

Module Church.
  Definition nat := forall X : Type, (X -> X) -> X -> X.

  Definition one : nat :=
    fun (X : Type) (f : X -> X) (x : X) => f x.

  Definition two : nat :=
    fun (X : Type) (f : X -> X) (x : X) => f (f x).

  Definition three : nat :=
    fun X f (x : X) => f (f (f x)).

  Definition zero : nat :=
    fun (X : Type) (f : X -> X) (x : X) => x.

  Definition succ (n : nat) : nat :=
    fun (X : Type) (f : X -> X) (x : X) => f (n X f x).

  Example succ_1 : succ zero = one.
  Proof. auto. Qed.

  Example succ_2 : succ one = two.
  Proof. auto. Qed.

  Definition plus (n m : nat) : nat :=
    fun X (f : X -> X) (x : X) => n X f (m X f x).

  Example plus_1 : plus zero one = one.
  Proof. auto. Qed.

  Definition mult (n m : nat) : nat :=
    fun X f => n X (m X f).

  Example mult_1 : mult one one = one.
  Proof. auto. Qed.

  Example mult_2 : mult zero (plus three three) = zero.
  Proof. auto. Qed.

  Example mult_3 : mult two three = plus three three.
  Proof. auto. Qed.

  Definition exp (n m : nat) : nat :=
    (*n nat (mult m) one.*)
    fun X => m ((X -> X) -> X -> X) ((fun n' m' f => n' (m' f)) (n X)) (one X).

  Example exp_1 : exp two two = plus two two.
  Proof. auto. Qed.
  Example exp_2 : exp three two = plus (mult two (mult two two)) one.
  Proof. auto. Qed.
  Example exp_3 : exp three zero = one.
  Proof. auto. Qed.

End Church.


Require Import Arith Omega.

Definition divides (n m:nat) := exists p:nat, p*n = m.

Lemma divides_O : forall n:nat, divides n 0.
Proof.
  intro n; exists 0; simpl; trivial.
Qed.

Lemma divides_plus : forall n m:nat, divides n m -> divides n (n+m).
Proof.
 intros n m H; elim H; intros q Hq.
 exists (S q) ; simpl; auto.
Qed.

Lemma not_divides_plus : forall n m:nat, ~ divides n m -> ~ divides n (n+m).
Proof.
 intros n m H; red; intro H'; elim H'; intro y.
 case y; simpl.
 intro H2; apply H.
 cut (m=0).
 intro H3; rewrite H3; apply divides_O.
 Require Omega.
 omega.
 intros n0 Hn0.
 apply H.
 exists n0.
 omega.
Qed.

Lemma not_divides_lt : forall n m:nat, 0<m ->  m<n -> ~ divides n m.
Proof.
 intros n m H H0 H1.
 elim H1; intros q Hq.
 rewrite <- Hq in H.
 rewrite <- Hq in H0.
 generalize H H0; case q.
 simpl.
 intros; absurd (0 < 0); auto with arith.
 clear H H0; intros y Hy Hy'.
 simpl in Hy'.
 absurd (n <= n + y * n); auto with arith.
Qed.

Lemma not_lt_2_divides : forall n m:nat, n <> 1 -> n < 2 -> 0 < m ->
                        ~ divides n m.
Proof.
 intros n m H H0; cut (n=0).
 intro e;rewrite e.
 case m.
 intro; absurd (0 < 0); auto with arith.
 intros n0 Hn0 H1.
 elim H1; intros q Hq.
 rewrite mult_0_r in Hq; discriminate Hq.
Require Import Omega.
 omega.
Qed.

Lemma le_plus_minus : forall n m:nat, le n m -> m = n+(m-n).
Proof.
 intros; omega.
Qed.

Lemma lt_lt_or_eq : forall n m:nat, n < S m ->  n<m \/  n=m.
Proof.
 intros; omega.
Qed.


(* @todo  add as an exercise *)

(** Returns smallest value of x less or equal than b such that (P b x).
    Otherwise returns b  *)

From hydras Require Import  primRec extEqualNat.
From Coq Require Import Min ArithRing Lia Compare_dec Arith Lia.

(** Please consider the following specification of the integer square root *)

Definition isqrt_spec n r := r * r <= n < S r * S r.

(** Prove the following function [isqrt] is a primitive recursive
    (inefficient) implementation of this specification *)

Section sqrtIsPR.

Let P (n r: nat) :=  Nat.ltb n (S r * S r).
Definition isqrt  := boundedSearch P .

Lemma sqrt_correct (n: nat) : isqrt_spec n (isqrt n).
Admitted.

Lemma issqrtIsPR : isPR 1 isqrt.
Admitted.

End sqrtIsPR.

(** Extra work :
   Define a faster implementation of [sqrt_spec], and prove your function is
   extensionnaly equal to [isqrt] (hence PR!)
 *)