(** * Logic: Logic in Coq *)

Set Warnings "-notation-overridden,-parsing".
Require Export Tactics.

(** In previous chapters, we have seen many examples of factual
    claims (_propositions_) and ways of presenting evidence of their
    truth (_proofs_).  In particular, we have worked extensively with
    _equality propositions_ of the form [e1 = e2], with
    implications ([P -> Q]), and with quantified propositions ([forall
    x, P]).  In this chapter, we will see how Coq can be used to carry
    out other familiar forms of logical reasoning.

    Before diving into details, let's talk a bit about the status of
    mathematical statements in Coq.  Recall that Coq is a _typed_
    language, which means that every sensible expression in its world
    has an associated type.  Logical claims are no exception: any
    statement we might try to prove in Coq has a type, namely [Prop],
    the type of _propositions_.  We can see this with the [Check]
    command: *)

Check 3 = 3.
(* ===> Prop *)

Check forall n m : nat, n + m = m + n.
(* ===> Prop *)

(** Note that _all_ syntactically well-formed propositions have type
    [Prop] in Coq, regardless of whether they are true. *)

(** Simply _being_ a proposition is one thing; being _provable_ is
    something else! *)

Check 2 = 2.
(* ===> Prop *)

Check forall n : nat, n = 2.
(* ===> Prop *)

Check 3 = 4.
(* ===> Prop *)

(** Indeed, propositions don't just have types: they are
    _first-class objects_ that can be manipulated in the same ways as
    the other entities in Coq's world. *)

(** So far, we've seen one primary place that propositions can appear:
    in [Theorem] (and [Lemma] and [Example]) declarations. *)
Theorem plus_2_2_is_4 :
  2 + 2 = 4.
Proof. reflexivity.  Qed.

(** But propositions can be used in many other ways.  For example, we
    can give a name to a proposition using a [Definition], just as we
    have given names to expressions of other sorts. *)

Definition plus_fact : Prop := 2 + 2 = 4.
Check plus_fact.
(* ===> plus_fact : Prop *)

(** We can later use this name in any situation where a proposition is
    expected -- for example, as the claim in a [Theorem] declaration. *)

Theorem plus_fact_is_true :
  plus_fact.
Proof. reflexivity.  Qed.

(** We can also write _parameterized_ propositions -- that is,
    functions that take arguments of some type and return a
    proposition. *)

(** For instance, the following function takes a number
    and returns a proposition asserting that this number is equal to
    three: *)

Definition is_three (n : nat) : Prop :=
  n = 3.
Check is_three.
(* ===> nat -> Prop *)

(** In Coq, functions that return propositions are said to define
    _properties_ of their arguments.

    For instance, here's a (polymorphic) property defining the
    familiar notion of an _injective function_. *)

Definition injective {A B} (f : A -> B) :=
  forall x y : A, f x = f y -> x = y.

Lemma succ_inj : injective S.
Proof.
  intros n m H. inversion H. reflexivity.
Qed.

(** The equality operator [=] is also a function that returns a
    [Prop].

    The expression [n = m] is syntactic sugar for [eq n m] (defined
    using Coq's [Notation] mechanism). Because [eq] can be used with
    elements of any type, it is also polymorphic: *)

Check @eq.
(* ===> forall A : Type, A -> A -> Prop *)

(** (Notice that we wrote [@eq] instead of [eq]: The type
    argument [A] to [eq] is declared as implicit, so we need to turn
    off implicit arguments to see the full type of [eq].) *)

(* ################################################################# *)
(** * Logical Connectives *)

(* ================================================================= *)
(** ** Conjunction *)

(** The _conjunction_ (or _logical and_) of propositions [A] and [B]
    is written [A /\ B], representing the claim that both [A] and [B]
    are true. *)

Example and_example : 3 + 4 = 7 /\ 2 * 2 = 4.

(** To prove a conjunction, use the [split] tactic.  It will generate
    two subgoals, one for each part of the statement: *)

Proof.
  (* WORKED IN CLASS *)
  split.
  - (* 3 + 4 = 7 *) reflexivity.
  - (* 2 + 2 = 4 *) reflexivity.
Qed.

(** For any propositions [A] and [B], if we assume that [A] is true
    and we assume that [B] is true, we can conclude that [A /\ B] is
    also true. *)

Lemma and_intro : forall A B : Prop, A -> B -> A /\ B.
Proof.
  intros A B HA HB. split.
  - apply HA.
  - apply HB.
Qed.

(** Since applying a theorem with hypotheses to some goal has the
    effect of generating as many subgoals as there are hypotheses for
    that theorem, we can apply [and_intro] to achieve the same effect
    as [split]. *)

Example and_example' : 3 + 4 = 7 /\ 2 * 2 = 4.
Proof.
  apply and_intro.
  - (* 3 + 4 = 7 *) reflexivity.
  - (* 2 + 2 = 4 *) reflexivity.
Qed.

(** **** Exercise: 2 stars (and_exercise)  *)
Example and_exercise :
  forall n m : nat, n + m = 0 -> n = 0 /\ m = 0.
Proof.
intros n m H.
split.
-
destruct n.
reflexivity.
inversion H.
-
destruct m.
reflexivity.
Search (?n + ?m).
rewrite <- plus_n_Sm in H.
inversion H.
Qed.

(** So much for proving conjunctive statements.  To go in the other
    direction -- i.e., to _use_ a conjunctive hypothesis to help prove
    something else -- we employ the [destruct] tactic.

    If the proof context contains a hypothesis [H] of the form
    [A /\ B], writing [destruct H as [HA HB]] will remove [H] from the
    context and add two new hypotheses: [HA], stating that [A] is
    true, and [HB], stating that [B] is true.  *)

Lemma and_example2 :
  forall n m : nat, n = 0 /\ m = 0 -> n + m = 0.
Proof.
  (* WORKED IN CLASS *)
  intros n m H.
  destruct H as [Hn Hm].
  rewrite Hn. rewrite Hm.
  reflexivity.
Qed.

(** As usual, we can also destruct [H] right when we introduce it,
    instead of introducing and then destructing it: *)

Lemma and_example2' :
  forall n m : nat, n = 0 /\ m = 0 -> n + m = 0.
Proof.
  intros n m [Hn Hm].
  rewrite Hn. rewrite Hm.
  reflexivity.
Qed.

(** You may wonder why we bothered packing the two hypotheses [n = 0]
    and [m = 0] into a single conjunction, since we could have also
    stated the theorem with two separate premises: *)

Lemma and_example2'' :
  forall n m : nat, n = 0 -> m = 0 -> n + m = 0.
Proof.
  intros n m Hn Hm.
  rewrite Hn. rewrite Hm.
  reflexivity.
Qed.

(** For this theorem, both formulations are fine.  But it's important
    to understand how to work with conjunctive hypotheses because
    conjunctions often arise from intermediate steps in proofs,
    especially in bigger developments.  Here's a simple example: *)

Lemma and_example3 :
  forall n m : nat, n + m = 0 -> n * m = 0.
Proof.
  (* WORKED IN CLASS *)
  intros n m H.
  assert (H' : n = 0 /\ m = 0).
  { apply and_exercise. apply H. }
  destruct H' as [Hn Hm].
  rewrite Hn. reflexivity.
Qed.

(** Another common situation with conjunctions is that we know
    [A /\ B] but in some context we need just [A] (or just [B]).
    The following lemmas are useful in such cases: *)

Lemma proj1 : forall P Q : Prop,
  P /\ Q -> P.
Proof.
  intros P Q [HP HQ].
  apply HP.  Qed.

(** **** Exercise: 1 star, optional (proj2)  *)
Lemma proj2 : forall P Q : Prop,
  P /\ Q -> Q.
Proof.
  intros P Q [HP HQ].
  apply HQ.  Qed.

(** Finally, we sometimes need to rearrange the order of conjunctions
    and/or the grouping of multi-way conjunctions.  The following
    commutativity and associativity theorems are handy in such
    cases. *)

Theorem and_commut : forall P Q : Prop,
  P /\ Q -> Q /\ P.
Proof.
  intros P Q [HP HQ].
  split.
    - (* left *) apply HQ.
    - (* right *) apply HP.  Qed.

(** **** Exercise: 2 stars (and_assoc)  *)
(** (In the following proof of associativity, notice how the _nested_
    intro pattern breaks the hypothesis [H : P /\ (Q /\ R)] down into
    [HP : P], [HQ : Q], and [HR : R].  Finish the proof from
    there.) *)

Theorem and_assoc : forall P Q R : Prop,
  P /\ (Q /\ R) -> (P /\ Q) /\ R.
Proof.
  intros P Q R [HP [HQ HR]].
  split.
split.
apply HP.
apply HQ.
apply HR.
Qed.

(** By the way, the infix notation [/\] is actually just syntactic
    sugar for [and A B].  That is, [and] is a Coq operator that takes
    two propositions as arguments and yields a proposition. *)

Check and.
(* ===> and : Prop -> Prop -> Prop *)

(* ================================================================= *)
(** ** Disjunction *)

(** Another important connective is the _disjunction_, or _logical or_
    of two propositions: [A \/ B] is true when either [A] or [B]
    is.  (Alternatively, we can write [or A B], where [or : Prop ->
    Prop -> Prop].) *)

(** To use a disjunctive hypothesis in a proof, we proceed by case
    analysis, which, as for [nat] or other data types, can be done
    with [destruct] or [intros].  Here is an example: *)

Lemma or_example :
  forall n m : nat, n = 0 \/ m = 0 -> n * m = 0.
Proof.
  (* This pattern implicitly does case analysis on
     [n = 0 \/ m = 0] *)
  intros n m [Hn | Hm].
  - (* Here, [n = 0] *)
    rewrite Hn. reflexivity.
  - (* Here, [m = 0] *)
    rewrite Hm. rewrite <- mult_n_O.
    reflexivity.
Qed.

(** Conversely, to show that a disjunction holds, we need to show that
    one of its sides does. This is done via two tactics, [left] and
    [right].  As their names imply, the first one requires
    proving the left side of the disjunction, while the second
    requires proving its right side.  Here is a trivial use... *)

Lemma or_intro : forall A B : Prop, A -> A \/ B.
Proof.
  intros A B HA.
  left.
  apply HA.
Qed.

(** ... and a slightly more interesting example requiring both [left]
    and [right]: *)

Lemma zero_or_succ :
  forall n : nat, n = 0 \/ n = S (pred n).
Proof.
  (* WORKED IN CLASS *)
  intros [|n].
  - left. reflexivity.
  - right. reflexivity.
Qed.

(** **** Exercise: 1 star (mult_eq_0)  *)
Lemma mult_eq_0 :
  forall n m, n * m = 0 -> n = 0 \/ m = 0.
Proof.
induction n.
  simpl. left. reflexivity.
induction m.
  simpl. right. reflexivity.
intros H.
inversion H.
Qed.

(** **** Exercise: 1 star (or_commut)  *)
Theorem or_commut : forall P Q : Prop,
  P \/ Q  -> Q \/ P.
Proof.
intros P Q [HP | HQ].
right.
apply HP.
left.
apply HQ.
Qed.

(* ================================================================= *)
(** ** Falsehood and Negation *)
(** So far, we have mostly been concerned with proving that certain
    things are _true_ -- addition is commutative, appending lists is
    associative, etc.  Of course, we may also be interested in
    _negative_ results, showing that certain propositions are _not_
    true. In Coq, such negative statements are expressed with the
    negation operator [~]. *)

(** To see how negation works, recall the discussion of the _principle
    of explosion_ from the [Tactics] chapter; it asserts that, if
    we assume a contradiction, then any other proposition can be
    derived.  Following this intuition, we could define [~ P] ("not
    [P]") as [forall Q, P -> Q].  Coq actually makes a slightly
    different choice, defining [~ P] as [P -> False], where [False] is
    a specific contradictory proposition defined in the standard
    library. *)

Module MyNot.

Definition not (P:Prop) := P -> False.

Notation "~ x" := (not x) : type_scope.

Check not.
(* ===> Prop -> Prop *)

End MyNot.

(** Since [False] is a contradictory proposition, the principle of
    explosion also applies to it. If we get [False] into the proof
    context, we can use [destruct] (or [inversion]) on it to complete
    any goal: *)

Theorem ex_falso_quodlibet : forall (P:Prop),
  False -> P.
Proof.
  (* WORKED IN CLASS *)
  intros P contra.
  destruct contra.  Qed.

(** The Latin _ex falso quodlibet_ means, literally, "from falsehood
    follows whatever you like"; this is another common name for the
    principle of explosion. *)

(** **** Exercise: 2 stars, optional (not_implies_our_not)  *)
(** Show that Coq's definition of negation implies the intuitive one
    mentioned above: *)

Fact not_implies_our_not : forall (P:Prop),
  ~ P -> (forall (Q:Prop), P -> Q).
Proof.
intros P NP Q PP.
destruct NP.
apply PP.
Qed.

(** This is how we use [not] to state that [0] and [1] are different
    elements of [nat]: *)

Theorem zero_not_one : ~(0 = 1).
Proof.
  intros contra. inversion contra.
Qed.

(** Such inequality statements are frequent enough to warrant a
    special notation, [x <> y]: *)

Check (0 <> 1).
(* ===> Prop *)

Theorem zero_not_one' : 0 <> 1.
Proof.
  intros H. inversion H.
Qed.

(** It takes a little practice to get used to working with negation in
    Coq.  Even though you can see perfectly well why a statement
    involving negation is true, it can be a little tricky at first to
    get things into the right configuration so that Coq can understand
    it!  Here are proofs of a few familiar facts to get you warmed
    up. *)

Theorem not_False :
  ~ False.
Proof.
  unfold not. intros H. destruct H. Qed.

Theorem contradiction_implies_anything : forall P Q : Prop,
  (P /\ ~P) -> Q.
Proof.
  (* WORKED IN CLASS *)
  intros P Q [HP HNA]. unfold not in HNA.
  apply HNA in HP. destruct HP.  Qed.

Theorem double_neg : forall P : Prop,
  P -> ~~P.
Proof.
  (* WORKED IN CLASS *)
  intros P H. unfold not. intros G. apply G. apply H.  Qed.

(** **** Exercise: 2 stars, advanced, recommended (double_neg_inf)  *)
(** Write an informal proof of [double_neg]:

   _Theorem_: [P] implies [~~P], for any proposition [P]. *)

(* FILL IN HERE *)
(** [] *)

(** **** Exercise: 2 stars, recommended (contrapositive)  *)
Theorem contrapositive : forall (P Q : Prop),
  (P -> Q) -> (~Q -> ~P).
Proof.
  intros P Q H NQ.
  unfold not.
  intros PP.
  unfold not in NQ.
  apply NQ in H.
  inversion H.
  apply PP.
  Qed.

(** **** Exercise: 1 star (not_both_true_and_false)  *)
Theorem not_both_true_and_false : forall P : Prop,
  ~ (P /\ ~P).
Proof.
  unfold not.
  intros P H.
  inversion H.
  apply H1 in H0.
  inversion H0.
  Qed.

  (** **** Exercise: 1 star, advanced (informal_not_PNP)  *)
Definition informal_not_PNP_TODO := 0.
(** Write an informal proof (in English) of the proposition [forall P
    : Prop, ~(P /\ ~P)]. *)

(* FILL IN HERE *)
(** [] *)

(** Similarly, since inequality involves a negation, it requires a
    little practice to be able to work with it fluently.  Here is one
    useful trick.  If you are trying to prove a goal that is
    nonsensical (e.g., the goal state is [false = true]), apply
    [ex_falso_quodlibet] to change the goal to [False].  This makes it
    easier to use assumptions of the form [~P] that may be available
    in the context -- in particular, assumptions of the form
    [x<>y]. *)

Theorem not_true_is_false : forall b : bool,
  b <> true -> b = false.
Proof.
  intros [] H.
  - (* b = true *)
    unfold not in H.
    apply ex_falso_quodlibet.
    apply H. reflexivity.
  - (* b = false *)
    reflexivity.
Qed.

(** Since reasoning with [ex_falso_quodlibet] is quite common, Coq
    provides a built-in tactic, [exfalso], for applying it. *)

Theorem not_true_is_false' : forall b : bool,
  b <> true -> b = false.
Proof.
  intros [] H.
  - (* b = false *)
    unfold not in H.
    exfalso.                (* <=== *)
    apply H. reflexivity.
  - (* b = true *) reflexivity.
Qed.

(* ================================================================= *)
(** ** Truth *)

(** Besides [False], Coq's standard library also defines [True], a
    proposition that is trivially true. To prove it, we use the
    predefined constant [I : True]: *)

Lemma True_is_true : True.
Proof. apply I. Qed.

(** Unlike [False], which is used extensively, [True] is used quite
    rarely, since it is trivial (and therefore uninteresting) to prove
    as a goal, and it carries no useful information as a hypothesis.
    But it can be quite useful when defining complex [Prop]s using
    conditionals or as a parameter to higher-order [Prop]s.  We will
    see examples of such uses of [True] later on.
*)

(* ================================================================= *)
(** ** Logical Equivalence *)

(** The handy "if and only if" connective, which asserts that two
    propositions have the same truth value, is just the conjunction of
    two implications. *)

Module MyIff.

Definition iff (P Q : Prop) := (P -> Q) /\ (Q -> P).

Notation "P <-> Q" := (iff P Q)
                      (at level 95, no associativity)
                      : type_scope.

End MyIff.

Theorem iff_sym : forall P Q : Prop,
  (P <-> Q) -> (Q <-> P).
Proof.
  (* WORKED IN CLASS *)
  intros P Q [HAB HBA].
  split.
  - (* -> *) apply HBA.
  - (* <- *) apply HAB.  Qed.

Lemma not_true_iff_false : forall b,
  b <> true <-> b = false.
Proof.
  (* WORKED IN CLASS *)
  intros b. split.
  - (* -> *) apply not_true_is_false.
  - (* <- *)
    intros H. rewrite H. intros H'. inversion H'.
Qed.

(** **** Exercise: 1 star, optional (iff_properties)  *)
(** Using the above proof that [<->] is symmetric ([iff_sym]) as
    a guide, prove that it is also reflexive and transitive. *)

Theorem iff_refl : forall P : Prop,
  P <-> P.
Proof.
split.
trivial.
trivial.
Qed.

Theorem iff_trans : forall P Q R : Prop,
  (P <-> Q) -> (Q <-> R) -> (P <-> R).
Proof.
intros P Q R PQ QR.
destruct QR.
destruct PQ.
split.
intros PP.
apply H1 in PP.
apply H in PP.
apply PP.
intros RR.
apply H0 in RR.
apply H2 in RR.
apply RR.
Qed.

(** **** Exercise: 3 stars (or_distributes_over_and)  *)
Theorem or_distributes_over_and : forall P Q R : Prop,
  P \/ (Q /\ R) <-> (P \/ Q) /\ (P \/ R).
Proof.
intros P Q R.
split.
-
intros H.
destruct H.
+
split.
*
left.
trivial.
*
left.
trivial.
+
split.
*
right.
apply H.
*
right.
apply H.
-
intros H.
inversion H as [[HP1 | HQ] [HP2 | HR]].
left. apply HP1.
left. apply HP1.
left. apply HP2.
right.
split.
trivial.
trivial.
Qed.

  (** Some of Coq's tactics treat [iff] statements specially, avoiding
    the need for some low-level proof-state manipulation.  In
    particular, [rewrite] and [reflexivity] can be used with [iff]
    statements, not just equalities.  To enable this behavior, we need
    to import a Coq library that supports it: *)

Require Import Coq.Setoids.Setoid.

(** Here is a simple example demonstrating how these tactics work with
    [iff].  First, let's prove a couple of basic iff equivalences... *)

Lemma mult_0 : forall n m, n * m = 0 <-> n = 0 \/ m = 0.
Proof.
  split.
  - apply mult_eq_0.
  - apply or_example.
Qed.

Lemma or_assoc :
  forall P Q R : Prop, P \/ (Q \/ R) <-> (P \/ Q) \/ R.
Proof.
  intros P Q R. split.
  - intros [H | [H | H]].
    + left. left. apply H.
    + left. right. apply H.
    + right. apply H.
  - intros [[H | H] | H].
    + left. apply H.
    + right. left. apply H.
    + right. right. apply H.
Qed.

(** We can now use these facts with [rewrite] and [reflexivity] to
    give smooth proofs of statements involving equivalences.  Here is
    a ternary version of the previous [mult_0] result: *)

Lemma mult_0_3 :
  forall n m p, n * m * p = 0 <-> n = 0 \/ m = 0 \/ p = 0.
Proof.
  intros n m p.
  rewrite mult_0. rewrite mult_0. rewrite or_assoc.
  reflexivity.
Qed.

(** The [apply] tactic can also be used with [<->]. When given an
    equivalence as its argument, [apply] tries to guess which side of
    the equivalence to use. *)

Lemma apply_iff_example :
  forall n m : nat, n * m = 0 -> n = 0 \/ m = 0.
Proof.
  intros n m H. apply mult_0. apply H.
Qed.

(* ================================================================= *)
(** ** Existential Quantification *)

(** Another important logical connective is _existential
    quantification_.  To say that there is some [x] of type [T] such
    that some property [P] holds of [x], we write [exists x : T,
    P]. As with [forall], the type annotation [: T] can be omitted if
    Coq is able to infer from the context what the type of [x] should
    be. *)

(** To prove a statement of the form [exists x, P], we must show that
    [P] holds for some specific choice of value for [x], known as the
    _witness_ of the existential.  This is done in two steps: First,
    we explicitly tell Coq which witness [t] we have in mind by
    invoking the tactic [exists t].  Then we prove that [P] holds after
    all occurrences of [x] are replaced by [t]. *)

Lemma four_is_even : exists n : nat, 4 = n + n.
Proof.
  exists 2. reflexivity.
Qed.

(** Conversely, if we have an existential hypothesis [exists x, P] in
    the context, we can destruct it to obtain a witness [x] and a
    hypothesis stating that [P] holds of [x]. *)

Theorem exists_example_2 : forall n,
  (exists m, n = 4 + m) ->
  (exists o, n = 2 + o).
Proof.
  (* WORKED IN CLASS *)
  intros n [m Hm]. (* note implicit [destruct] here *)
  exists (2 + m).
  apply Hm.  Qed.

(** **** Exercise: 1 star, recommended (dist_not_exists)  *)
(** Prove that "[P] holds for all [x]" implies "there is no [x] for
    which [P] does not hold."  (Hint: [destruct H as [x E]] works on
    existential assumptions!)  *)

Theorem dist_not_exists : forall (X:Type) (P : X -> Prop),
  (forall x, P x) -> ~ (exists x, ~ P x).
Proof.
intros X P x.
unfold not.
intros x0.
inversion x0. destruct H.
apply x.
Qed.

(** **** Exercise: 2 stars (dist_exists_or)  *)
(** Prove that existential quantification distributes over
    disjunction. *)

Theorem dist_exists_or : forall (X:Type) (P Q : X -> Prop),
  (exists x, P x \/ Q x) <-> (exists x, P x) \/ (exists x, Q x).
Proof.
intros X P Q.
split.
-
intros x.
inversion x.
destruct H.
+
left.
exists x0.
apply H.
+
right.
exists x0.
exact H.
-
intros H.
destruct H.
+
inversion H.
exists x.
left.
exact H0.
+
inversion H.
exists x.
right.
exact H0.
Qed.

(* ################################################################# *)
(** * Programming with Propositions *)

(** The logical connectives that we have seen provide a rich
    vocabulary for defining complex propositions from simpler ones.
    To illustrate, let's look at how to express the claim that an
    element [x] occurs in a list [l].  Notice that this property has a
    simple recursive structure: *)
(**    - If [l] is the empty list, then [x] cannot occur on it, so the
         property "[x] appears in [l]" is simply false. *)
(**    - Otherwise, [l] has the form [x' :: l'].  In this case, [x]
         occurs in [l] if either it is equal to [x'] or it occurs in
         [l']. *)

(** We can translate this directly into a straightforward recursive
    function taking an element and a list and returning a proposition: *)

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

Fixpoint In {A : Type} (x : A) (l : list A) : Prop :=
  match l with
  | []  => False
  | x' :: l' => x' = x \/ In x l'
  end.

(** When [In] is applied to a concrete list, it expands into a
    concrete sequence of nested disjunctions. *)

Example In_example_1 : In 4 [1; 2; 3; 4; 5].
Proof.
  (* WORKED IN CLASS *)
  simpl. right. right. right. left. reflexivity.
Qed.

Example In_example_2 :
  forall n, In n [2; 4] ->
  exists n', n = 2 * n'.
Proof.
  (* WORKED IN CLASS *)
  simpl.
  intros n [H | [H | []]].
  - exists 1. rewrite <- H. reflexivity.
  - exists 2. rewrite <- H. reflexivity.
Qed.
(** (Notice the use of the empty pattern to discharge the last case
    _en passant_.) *)

(** We can also prove more generic, higher-level lemmas about [In].

    Note, in the next, how [In] starts out applied to a variable and
    only gets expanded when we do case analysis on this variable: *)

Fixpoint map {X Y:Type} (f:X -> Y) (l:list X) : (list Y) :=
  match l with
  | [] => []
  | h :: t => (f h) :: (map f t)
  end.

Lemma In_map :
  forall (A B : Type) (f : A -> B) (l : list A) (x : A),
    In x l ->
    In (f x) (map f l).
Proof.
  intros A B f l x.
  induction l as [|x' l' IHl'].
  - (* l = nil, contradiction *)
    simpl.
    intros [].
  - (* l = x' :: l' *)
    simpl. intros [H | H].
    + rewrite H. left. reflexivity.
    + right. apply IHl'. apply H.
Qed.

(** This way of defining propositions recursively, though convenient
    in some cases, also has some drawbacks.  In particular, it is
    subject to Coq's usual restrictions regarding the definition of
    recursive functions, e.g., the requirement that they be "obviously
    terminating."  In the next chapter, we will see how to define
    propositions _inductively_, a different technique with its own set
    of strengths and limitations. *)

(** **** Exercise: 2 stars (In_map_iff)  *)
 Lemma In_map_iff :
  forall (A B : Type) (f : A -> B) (l : list A) (y : B),
    In y (map f l) <->
    exists x, f x = y /\ In x l.
Proof.
intros A B f l y.
split.
-
intros H.
induction l.
+
simpl in H.
inversion H.
+
simpl in H.
destruct H as [H1 | H2].
*
  exists x.
  split.
  exact H1.
  simpl.
  left.
  reflexivity.
*
  apply IHl in H2.
  destruct H2 as [x2 H2].
  exists x2.
  split.
  apply proj1 in H2. exact H2.
  apply proj2 in H2. simpl. right. exact H2.
-
intros H.
induction l.
+
  simpl in H.
  simpl.
  destruct H.
  apply proj2 in H. exact H.
+
  simpl.
  destruct H.
  destruct H.
  destruct H0.
  rewrite <- H0 in H.
  left. exact H.
  right. apply IHl. exists x0. split. exact H. exact H0.
Qed.

(** **** Exercise: 2 stars (In_app_iff)  *)
Lemma In_app_iff : forall A l l' (a:A),
  In a (l++l') <-> In a l \/ In a l'.
Proof.
intros A l1 l2 a.
split.
-
intros H. induction l1.
+
simpl. simpl in H. right. exact H.
+
simpl. simpl in H. destruct H.
*
left. left. exact H.
*
apply IHl1 in H.
destruct H.
left. right. exact H.
right. exact H.
-
intros H.
induction l1.
+
simpl in H. simpl. destruct H.
inversion H. exact H.
+
simpl. simpl in H. apply or_assoc in H. destruct H.
*
left. exact H.
*
right. apply IHl1. exact H.
Qed.

(** **** Exercise: 3 stars, recommended (All)  *)
(** Recall that functions returning propositions can be seen as
    _properties_ of their arguments. For instance, if [P] has type
    [nat -> Prop], then [P n] states that property [P] holds of [n].

    Drawing inspiration from [In], write a recursive function [All]
    stating that some property [P] holds of all elements of a list
    [l]. To make sure your definition is correct, prove the [All_In]
    lemma below.  (Of course, your definition should _not_ just
    restate the left-hand side of [All_In].) *)

Fixpoint All {T : Type} (P : T -> Prop) (l : list T) : Prop
  (* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.

Lemma All_In :
  forall T (P : T -> Prop) (l : list T),
    (forall x, In x l -> P x) <->
    All P l.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars (combine_odd_even)  *)
(** Complete the definition of the [combine_odd_even] function below.
    It takes as arguments two properties of numbers, [Podd] and
    [Peven], and it should return a property [P] such that [P n] is
    equivalent to [Podd n] when [n] is odd and equivalent to [Peven n]
    otherwise. *)

Definition combine_odd_even (Podd Peven : nat -> Prop) : nat -> Prop :=
fun x => if (oddb x) then Podd x else Peven x.

(** To test your definition, prove the following facts: *)

Theorem combine_odd_even_intro :
  forall (Podd Peven : nat -> Prop) (n : nat),
    (oddb n = true -> Podd n) ->
    (oddb n = false -> Peven n) ->
    combine_odd_even Podd Peven n.
Proof.
  intros Podd Peven n.
  unfold oddb.
  intros odd.
  intros even.
induction n.
-
unfold combine_odd_even.
unfold oddb.
apply even.
simpl.
reflexivity.
-
unfold combine_odd_even.
unfold oddb.
destruct evenb.
+
apply even.
simpl.
reflexivity.
+
apply odd.
simpl.
reflexivity.
Qed.

Theorem combine_odd_even_elim_odd :
  forall (Podd Peven : nat -> Prop) (n : nat),
    combine_odd_even Podd Peven n ->
    oddb n = true ->
    Podd n.
Proof.
intros Podd Peven n.
intros H odd.
unfold combine_odd_even in H.
rewrite odd in H.
exact H.
Qed.

Theorem combine_odd_even_elim_even :
  forall (Podd Peven : nat -> Prop) (n : nat),
    combine_odd_even Podd Peven n ->
    oddb n = false ->
    Peven n.
Proof.
intros Podd Peven n.
intros H odd.
unfold combine_odd_even in H.
rewrite odd in H.
exact H.
Qed.

(* ################################################################# *)
(** * Applying Theorems to Arguments *)

(** One feature of Coq that distinguishes it from many other proof
    assistants is that it treats _proofs_ as first-class objects.

    There is a great deal to be said about this, but it is not
    necessary to understand it in detail in order to use Coq.  This
    section gives just a taste, while a deeper exploration can be
    found in the optional chapters [ProofObjects] and
    [IndPrinciples]. *)

(** We have seen that we can use the [Check] command to ask Coq to
    print the type of an expression.  We can also use [Check] to ask
    what theorem a particular identifier refers to. *)

Check plus_comm.
(* ===> forall n m : nat, n + m = m + n *)

(** Coq prints the _statement_ of the [plus_comm] theorem in the same
    way that it prints the _type_ of any term that we ask it to
    [Check].  Why? *)

(**  The reason is that the identifier [plus_comm] actually refers to a
    _proof object_ -- a data structure that represents a logical
    derivation establishing of the truth of the statement [forall n m
    : nat, n + m = m + n].  The type of this object _is_ the statement
    of the theorem that it is a proof of. *)

(** Intuitively, this makes sense because the statement of a theorem
    tells us what we can use that theorem for, just as the type of a
    computational object tells us what we can do with that object --
    e.g., if we have a term of type [nat -> nat -> nat], we can give
    it two [nat]s as arguments and get a [nat] back.  Similarly, if we
    have an object of type [n = m -> n + n = m + m] and we provide it
    an "argument" of type [n = m], we can derive [n + n = m + m]. *)

(** Operationally, this analogy goes even further: by applying a
    theorem, as if it were a function, to hypotheses with matching
    types, we can specialize its result without having to resort to
    intermediate assertions.  For example, suppose we wanted to prove
    the following result: *)

Lemma plus_comm3 :
  forall x y z, x + (y + z) = (z + y) + x.

(** It appears at first sight that we ought to be able to prove this
    by rewriting with [plus_comm] twice to make the two sides match.
    The problem, however, is that the second [rewrite] will undo the
    effect of the first. *)

Proof.
  intros x y z.
  rewrite plus_comm.
  rewrite plus_comm.
  (* We are back where we started... *)
Abort.

(** One simple way of fixing this problem, using only tools that we
    already know, is to use [assert] to derive a specialized version
    of [plus_comm] that can be used to rewrite exactly where we
    want. *)

Lemma plus_comm3_take2 :
  forall x y z, x + (y + z) = (z + y) + x.
Proof.
  intros x y z.
  rewrite plus_comm.
  assert (H : y + z = z + y).
  { rewrite plus_comm. reflexivity. }
  rewrite H.
  reflexivity.
Qed.

(** A more elegant alternative is to apply [plus_comm] directly to the
    arguments we want to instantiate it with, in much the same way as
    we apply a polymorphic function to a type argument. *)

Lemma plus_comm3_take3 :
  forall x y z, x + (y + z) = (z + y) + x.
Proof.
  intros x y z.
  rewrite plus_comm.
  rewrite (plus_comm y z).
  reflexivity.
Qed.

(** You can "use theorems as functions" in this way with almost all
    tactics that take a theorem name as an argument.  Note also that
    theorem application uses the same inference mechanisms as function
    application; thus, it is possible, for example, to supply
    wildcards as arguments to be inferred, or to declare some
    hypotheses to a theorem as implicit by default.  These features
    are illustrated in the proof below. *)

Example lemma_application_ex :
  forall {n : nat} {ns : list nat},
    In n (map (fun m => m * 0) ns) ->
    n = 0.
Proof.
  intros n ns H.
  destruct (proj1 _ _ (In_map_iff _ _ _ _ _) H)
           as [m [Hm _]].
  rewrite mult_0_r in Hm. rewrite <- Hm. reflexivity.
Qed.

(** We will see many more examples of the idioms from this section in
    later chapters. *)

(* ################################################################# *)
(** * Coq vs. Set Theory *)

(** Coq's logical core, the _Calculus of Inductive Constructions_,
    differs in some important ways from other formal systems that are
    used by mathematicians for writing down precise and rigorous
    proofs.  For example, in the most popular foundation for
    mainstream paper-and-pencil mathematics, Zermelo-Fraenkel Set
    Theory (ZFC), a mathematical object can potentially be a member of
    many different sets; a term in Coq's logic, on the other hand, is
    a member of at most one type.  This difference often leads to
    slightly different ways of capturing informal mathematical
    concepts, but these are, by and large, quite natural and easy to
    work with.  For example, instead of saying that a natural number
    [n] belongs to the set of even numbers, we would say in Coq that
    [ev n] holds, where [ev : nat -> Prop] is a property describing
    even numbers.

    However, there are some cases where translating standard
    mathematical reasoning into Coq can be either cumbersome or
    sometimes even impossible, unless we enrich the core logic with
    additional axioms.  We conclude this chapter with a brief
    discussion of some of the most significant differences between the
    two worlds. *)

(* ================================================================= *)
(** ** Functional Extensionality *)

(** The equality assertions that we have seen so far mostly have
    concerned elements of inductive types ([nat], [bool], etc.).  But
    since Coq's equality operator is polymorphic, these are not the
    only possibilities -- in particular, we can write propositions
    claiming that two _functions_ are equal to each other: *)

Example function_equality_ex1 : plus 3 = plus (pred 4).
Proof. reflexivity. Qed.

(** In common mathematical practice, two functions [f] and [g] are
    considered equal if they produce the same outputs:

    (forall x, f x = g x) -> f = g

    This is known as the principle of _functional extensionality_.

    Informally speaking, an "extensional property" is one that
    pertains to an object's observable behavior.  Thus, functional
    extensionality simply means that a function's identity is
    completely determined by what we can observe from it -- i.e., in
    Coq terms, the results we obtain after applying it.

    Functional extensionality is not part of Coq's basic axioms.  This
    means that some "reasonable" propositions are not provable. *)

Example function_equality_ex2 :
  (fun x => plus x 1) = (fun x => plus 1 x).
Proof.
   (* Stuck *)
Abort.

(** However, we can add functional extensionality to Coq's core logic
    using the [Axiom] command. *)

Axiom functional_extensionality : forall {X Y: Type}
                                    {f g : X -> Y},
  (forall (x:X), f x = g x) -> f = g.

(** Using [Axiom] has the same effect as stating a theorem and
    skipping its proof using [Admitted], but it alerts the reader that
    this isn't just something we're going to come back and fill in
    later! *)

(** We can now invoke functional extensionality in proofs: *)

Example function_equality_ex2 :
  (fun x => plus x 1) = (fun x => plus 1 x).
Proof.
  apply functional_extensionality. intros x.
  apply plus_comm.
Qed.

(** Naturally, we must be careful when adding new axioms into Coq's
    logic, as they may render it _inconsistent_ -- that is, they may
    make it possible to prove every proposition, including [False]!

    Unfortunately, there is no simple way of telling whether an axiom
    is safe to add: hard work is generally required to establish the
    consistency of any particular combination of axioms.

    Fortunately, it is known that adding functional extensionality, in
    particular, _is_ consistent. *)

(** To check whether a particular proof relies on any additional
    axioms, use the [Print Assumptions] command.  *)

Print Assumptions function_equality_ex2.
(* ===>
     Axioms:
     functional_extensionality :
         forall (X Y : Type) (f g : X -> Y),
                (forall x : X, f x = g x) -> f = g *)

(** **** Exercise: 4 stars (tr_rev_correct)  *)
(** One problem with the definition of the list-reversing function
    [rev] that we have is that it performs a call to [app] on each
    step; running [app] takes time asymptotically linear in the size
    of the list, which means that [rev] has quadratic running time.
    We can improve this with the following definition: *)

Fixpoint rev_append {X} (l1 l2 : list X) : list X :=
  match l1 with
  | [] => l2
  | x :: l1' => rev_append l1' (x :: l2)
  end.

Definition tr_rev {X} (l : list X) : list X :=
  rev_append l [].

(** This version is said to be _tail-recursive_, because the recursive
    call to the function is the last operation that needs to be
    performed (i.e., we don't have to execute [++] after the recursive
    call); a decent compiler will generate very efficient code in this
    case.  Prove that the two definitions are indeed equivalent. *)

Lemma tr_rev_correct : forall X, @tr_rev X = @rev X.
Proof.
intros X.
apply  functional_extensionality.
intros x.
induction x.
-
unfold tr_rev.
simpl.
reflexivity.
-
Abort.

(* ================================================================= *)
(** ** Propositions and Booleans *)

(** We've seen two different ways of encoding logical facts in Coq:
    with _booleans_ (of type [bool]), and with _propositions_ (of type
    [Prop]).

    For instance, to claim that a number [n] is even, we can say
    either
       - (1) that [evenb n] returns [true], or
       - (2) that there exists some [k] such that [n = double k].
             Indeed, these two notions of evenness are equivalent, as
             can easily be shown with a couple of auxiliary lemmas.

    Of course, it would be very strange if these two characterizations
    of evenness did not describe the same set of natural numbers!
    Fortunately, we can prove that they do... *)

(** We first need two helper lemmas. *)
Theorem evenb_double : forall k, evenb (double k) = true.
Proof.
  intros k. induction k as [|k' IHk'].
  - reflexivity.
  - simpl. apply IHk'.
Qed.

(** **** Exercise: 3 stars (evenb_double_conv)  *)
Theorem evenb_double_conv : forall n,
  exists k, n = if evenb n then double k
                else S (double k).
Proof.
  Check @evenb_S.
  intros n.
  exists n.
  induction n.
  -
simpl. reflexivity.
-
rewrite evenb_S.
simpl.
inversion IHn.
Abort.
  (* Hint: Use the [evenb_S] lemma from [Induction.v]. *)
  (* FILL IN HERE *)

(** Theorem even_bool_prop : forall n,
  evenb n = true <-> exists k, n = double k.
Proof.
  intros n. split.
  - intros H. destruct (evenb_double_conv n) as [k Hk].
    rewrite Hk. rewrite H. exists k. reflexivity.
  - intros [k Hk]. rewrite Hk. apply evenb_double.
Qed.
**)

(** In view of this theorem, we say that the boolean
    computation [evenb n] _reflects_ the logical proposition
    [exists k, n = double k]. *)

(** Similarly, to state that two numbers [n] and [m] are equal, we can
    say either (1) that [beq_nat n m] returns [true] or (2) that [n =
    m].  Again, these two notions are equivalent. *)

Theorem beq_nat_true_iff : forall n1 n2 : nat,
  beq_nat n1 n2 = true <-> n1 = n2.
Proof.
  intros n1 n2. split.
  - apply beq_nat_true.
  - intros H. rewrite H. rewrite <- beq_nat_refl. reflexivity.
Qed.

(** However, even when the boolean and propositional formulations of a
    claim are equivalent from a purely logical perspective, they need
    not be equivalent _operationally_.

    Equality provides an extreme example: knowing that [beq_nat n m =
    true] is generally of little direct help in the middle of a proof
    involving [n] and [m]; however, if we convert the statement to the
    equivalent form [n = m], we can rewrite with it. *)

(** The case of even numbers is also interesting.  Recall that,
    when proving the backwards direction of [even_bool_prop] (i.e.,
    [evenb_double], going from the propositional to the boolean
    claim), we used a simple induction on [k].  On the other hand, the
    converse (the [evenb_double_conv] exercise) required a clever
    generalization, since we can't directly prove [(exists k, n =
    double k) -> evenb n = true]. *)

(** For these examples, the propositional claims are more useful than
    their boolean counterparts, but this is not always the case.  For
    instance, we cannot test whether a general proposition is true or
    not in a function definition; as a consequence, the following code
    fragment is rejected: *)

Fail Definition is_even_prime n :=
  if n = 2 then true
  else false.

(** Coq complains that [n = 2] has type [Prop], while it expects an
    elements of [bool] (or some other inductive type with two
    elements).  The reason for this error message has to do with the
    _computational_ nature of Coq's core language, which is designed
    so that every function that it can express is computable and
    total.  One reason for this is to allow the extraction of
    executable programs from Coq developments.  As a consequence,
    [Prop] in Coq does _not_ have a universal case analysis operation
    telling whether any given proposition is true or false, since such
    an operation would allow us to write non-computable functions.

    Although general non-computable properties cannot be phrased as
    boolean computations, it is worth noting that even many
    _computable_ properties are easier to express using [Prop] than
    [bool], since recursive function definitions are subject to
    significant restrictions in Coq.  For instance, the next chapter
    shows how to define the property that a regular expression matches
    a given string using [Prop].  Doing the same with [bool] would
    amount to writing a regular expression matcher, which would be
    more complicated, harder to understand, and harder to reason
    about.

    Conversely, an important side benefit of stating facts using
    booleans is enabling some proof automation through computation
    with Coq terms, a technique known as _proof by
    reflection_.  Consider the following statement: *)

Example even_1000 : exists k, 1000 = double k.

(** The most direct proof of this fact is to give the value of [k]
    explicitly. *)

Proof. exists 500. reflexivity. Qed.

(** On the other hand, the proof of the corresponding boolean
    statement is even simpler: *)

Example even_1000' : evenb 1000 = true.
Proof. reflexivity. Qed.

(** What is interesting is that, since the two notions are equivalent,
    we can use the boolean formulation to prove the other one without
    mentioning the value 500 explicitly: *)

(** Example even_1000'' : exists k, 1000 = double k.
Proof. apply even_bool_prop. reflexivity. Qed. **)

(** Although we haven't gained much in terms of proof size in this
    case, larger proofs can often be made considerably simpler by the
    use of reflection.  As an extreme example, the Coq proof of the
    famous _4-color theorem_ uses reflection to reduce the analysis of
    hundreds of different cases to a boolean computation.  We won't
    cover reflection in great detail, but it serves as a good example
    showing the complementary strengths of booleans and general
    propositions. *)

(** **** Exercise: 2 stars (logical_connectives)  *)
(** The following lemmas relate the propositional connectives studied
    in this chapter to the corresponding boolean operations. *)

Notation "x && y" := (andb x y).
Notation "x || y" := (orb x y).

Lemma andb_true_iff : forall b1 b2:bool,
  b1 && b2 = true <-> b1 = true /\ b2 = true.
Proof.
intros b1 b2.
split.
-
intros H.
split.
destruct b1.
reflexivity.
inversion H.
destruct b2.
reflexivity.
rewrite <- H.
rewrite andb_false_r in H.
inversion H.
-
intros H.
destruct H.
rewrite H.
rewrite H0.
reflexivity.
Qed.

Lemma orb_true_iff : forall b1 b2,
  b1 || b2 = true <-> b1 = true \/ b2 = true.
Proof.
intros b1 b2.
split.
-
intros H.
destruct b1.
+
left. reflexivity.
+
right. apply H.
-
intros H.
destruct H.
+ rewrite H. reflexivity.
+ rewrite H.
Search (?a || ?b).
assert (or_com: forall (b:bool),  b|| true = true || b).
*
intros b. destruct b. reflexivity. reflexivity.
*
rewrite or_com. reflexivity.
Qed.
(** [] *)

(** **** Exercise: 1 star (beq_nat_false_iff)  *)
(** The following theorem is an alternate "negative" formulation of
    [beq_nat_true_iff] that is more convenient in certain
    situations (we'll see examples in later chapters). *)

Theorem beq_nat_false_iff : forall x y : nat,
  beq_nat x y = false <-> x <> y.
Proof.
intros x y.
unfold not.
split.
-
intros H H2.
apply beq_nat_true_iff in H2.
rewrite H2 in H.
inversion H.
-
intros H.
induction x.
+
induction y.
exfalso.
apply H.
reflexivity.
simpl.
reflexivity.
+
induction y.
simpl. reflexivity.
simpl.
destruct (beq_nat x y) eqn:HH.
exfalso. apply H. apply f_equal. apply beq_nat_true_iff. apply HH.
reflexivity.
Qed.

(** [] *)

(** **** Exercise: 3 stars (beq_list)  *)
(** Given a boolean operator [beq] for testing equality of elements of
    some type [A], we can define a function [beq_list beq] for testing
    equality of lists with elements in [A].  Complete the definition
    of the [beq_list] function below.  To make sure that your
    definition is correct, prove the lemma [beq_list_true_iff]. *)

Fixpoint beq_list {A : Type} (beq : A -> A -> bool)
         (l1 l2 : list A) : bool :=
    match l1, l2 with
  | [], [] => true
  | [], h::tl => false
  | h::tl, [] => false
  | h1::tl1, h2::tl2 => if (beq h1 h2) then beq_list beq tl1 tl2 else false
  end.

Lemma beq_list_true_iff :
  forall A (beq : A -> A -> bool),
    (forall a1 a2, beq a1 a2 = true <-> a1 = a2) ->
    forall l1 l2, beq_list beq l1 l2 = true <-> l1 = l2.
Proof.
 (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 2 stars, recommended (All_forallb)  *)
(** Recall the function [forallb], from the exercise
    [forall_exists_challenge] in chapter [Tactics]: *)

Fixpoint forallb {X : Type} (test : X -> bool) (l : list X) : bool :=
  match l with
  | [] => true
  | x :: l' => andb (test x) (forallb test l')
  end.

(** Prove the theorem below, which relates [forallb] to the [All]
    property of the above exercise. *)

Theorem forallb_true_iff : forall X test (l : list X),
   forallb test l = true <-> All (fun x => test x = true) l.
Proof.
  (* FILL IN HERE *) Admitted.

(** Are there any important properties of the function [forallb] which
    are not captured by this specification? *)

(* FILL IN HERE *)
(** [] *)

(* ================================================================= *)
(** ** Classical vs. Constructive Logic *)

(** We have seen that it is not possible to test whether or not a
    proposition [P] holds while defining a Coq function.  You may be
    surprised to learn that a similar restriction applies to _proofs_!
    In other words, the following intuitive reasoning principle is not
    derivable in Coq: *)

Definition excluded_middle := forall P : Prop,
  P \/ ~ P.

(** To understand operationally why this is the case, recall
    that, to prove a statement of the form [P \/ Q], we use the [left]
    and [right] tactics, which effectively require knowing which side
    of the disjunction holds.  But the universally quantified [P] in
    [excluded_middle] is an _arbitrary_ proposition, which we know
    nothing about.  We don't have enough information to choose which
    of [left] or [right] to apply, just as Coq doesn't have enough
    information to mechanically decide whether [P] holds or not inside
    a function. *)

(** However, if we happen to know that [P] is reflected in some
    boolean term [b], then knowing whether it holds or not is trivial:
    we just have to check the value of [b]. *)

Theorem restricted_excluded_middle : forall P b,
  (P <-> b = true) -> P \/ ~ P.
Proof.
  intros P [] H.
  - left. rewrite H. reflexivity.
  - right. rewrite H. intros contra. inversion contra.
Qed.

(** In particular, the excluded middle is valid for equations [n = m],
    between natural numbers [n] and [m]. *)

Theorem restricted_excluded_middle_eq : forall (n m : nat),
  n = m \/ n <> m.
Proof.
  intros n m.
  apply (restricted_excluded_middle (n = m) (beq_nat n m)).
  symmetry.
  apply beq_nat_true_iff.
Qed.

(** It may seem strange that the general excluded middle is not
    available by default in Coq; after all, any given claim must be
    either true or false.  Nonetheless, there is an advantage in not
    assuming the excluded middle: statements in Coq can make stronger
    claims than the analogous statements in standard mathematics.
    Notably, if there is a Coq proof of [exists x, P x], it is
    possible to explicitly exhibit a value of [x] for which we can
    prove [P x] -- in other words, every proof of existence is
    necessarily _constructive_. *)

(** Logics like Coq's, which do not assume the excluded middle, are
    referred to as _constructive logics_.

    More conventional logical systems such as ZFC, in which the
    excluded middle does hold for arbitrary propositions, are referred
    to as _classical_. *)

(** The following example illustrates why assuming the excluded middle
    may lead to non-constructive proofs:

    _Claim_: There exist irrational numbers [a] and [b] such that [a ^
    b] is rational.

    _Proof_: It is not difficult to show that [sqrt 2] is irrational.
    If [sqrt 2 ^ sqrt 2] is rational, it suffices to take [a = b =
    sqrt 2] and we are done.  Otherwise, [sqrt 2 ^ sqrt 2] is
    irrational.  In this case, we can take [a = sqrt 2 ^ sqrt 2] and
    [b = sqrt 2], since [a ^ b = sqrt 2 ^ (sqrt 2 * sqrt 2) = sqrt 2 ^
    2 = 2].  []

    Do you see what happened here?  We used the excluded middle to
    consider separately the cases where [sqrt 2 ^ sqrt 2] is rational
    and where it is not, without knowing which one actually holds!
    Because of that, we wind up knowing that such [a] and [b] exist
    but we cannot determine what their actual values are (at least,
    using this line of argument).

    As useful as constructive logic is, it does have its limitations:
    There are many statements that can easily be proven in classical
    logic but that have much more complicated constructive proofs, and
    there are some that are known to have no constructive proof at
    all!  Fortunately, like functional extensionality, the excluded
    middle is known to be compatible with Coq's logic, allowing us to
    add it safely as an axiom.  However, we will not need to do so in
    this book: the results that we cover can be developed entirely
    within constructive logic at negligible extra cost.

    It takes some practice to understand which proof techniques must
    be avoided in constructive reasoning, but arguments by
    contradiction, in particular, are infamous for leading to
    non-constructive proofs.  Here's a typical example: suppose that
    we want to show that there exists [x] with some property [P],
    i.e., such that [P x].  We start by assuming that our conclusion
    is false; that is, [~ exists x, P x]. From this premise, it is not
    hard to derive [forall x, ~ P x].  If we manage to show that this
    intermediate fact results in a contradiction, we arrive at an
    existence proof without ever exhibiting a value of [x] for which
    [P x] holds!

    The technical flaw here, from a constructive standpoint, is that
    we claimed to prove [exists x, P x] using a proof of
    [~ ~ (exists x, P x)].  Allowing ourselves to remove double
    negations from arbitrary statements is equivalent to assuming the
    excluded middle, as shown in one of the exercises below.  Thus,
    this line of reasoning cannot be encoded in Coq without assuming
    additional axioms. *)

(** **** Exercise: 3 stars (excluded_middle_irrefutable)  *)
(** Proving the consistency of Coq with the general excluded middle
    axiom requires complicated reasoning that cannot be carried out
    within Coq itself.  However, the following theorem implies that it
    is always safe to assume a decidability axiom (i.e., an instance
    of excluded middle) for any _particular_ Prop [P].  Why?  Because
    we cannot prove the negation of such an axiom.  If we could, we
    would have both [~ (P \/ ~P)] and [~ ~ (P \/ ~P)] (since [P]
    implies [~ ~ P], by the exercise below), which would be a
    contradiction.  But since we can't, it is safe to add [P \/ ~P] as
    an axiom. *)

Theorem excluded_middle_irrefutable: forall (P:Prop),
  ~ ~ (P \/ ~ P).
Proof.
intros P.
unfold not.
intros H.
apply H.
right.
intros HH.
apply H.
left.
apply HH.
Qed.
(** [] *)

(** **** Exercise: 3 stars, advanced (not_exists_dist)  *)
(** It is a theorem of classical logic that the following two
    assertions are equivalent:

    ~ (exists x, ~ P x)
    forall x, P x

    The [dist_not_exists] theorem above proves one side of this
    equivalence. Interestingly, the other direction cannot be proved
    in constructive logic. Your job is to show that it is implied by
    the excluded middle. *)

Theorem not_exists_dist :
  excluded_middle ->
  forall (X:Type) (P : X -> Prop),
    ~ (exists x, ~ P x) -> (forall x, P x).
Proof.
(* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 5 stars, optional (classical_axioms)  *)
(** For those who like a challenge, here is an exercise taken from the
    Coq'Art book by Bertot and Casteran (p. 123).  Each of the
    following four statements, together with [excluded_middle], can be
    considered as characterizing classical logic.  We can't prove any
    of them in Coq, but we can consistently add any one of them as an
    axiom if we wish to work in classical logic.

    Prove that all five propositions (these four plus
    [excluded_middle]) are equivalent. *)

Definition peirce := forall P Q: Prop,
  ((P->Q)->P)->P.

Definition double_negation_elimination := forall P:Prop,
  ~~P -> P.

Definition de_morgan_not_and_not := forall P Q:Prop,
  ~(~P /\ ~Q) -> P\/Q.

Definition implies_to_or := forall P Q:Prop,
  (P->Q) -> (~P\/Q).

(* FILL IN HERE *)

(** $Date: 2017-11-14 17:52:45 -0500 (Tue, 14 Nov 2017) $ *)


(* Coq Advent Calender *)
(* http://study-func-prog.blogspot.com/2010/12/coq-coq-advent-calender-reflexivity-25.html *)

(* 1/25 apply *)
(*
   「この仮定（下記の例では pq）を使うとゴール（下記の例では Q）が出て来る」という時に、
   apply pq とすると、ゴール Q が変化します。学校で習う普通の証明の順序と違って、
   Coqの証明はゴールを一歩一歩、仮定に戻して行きます。その時使うのが apply です。
*)

Lemma Sample_of_apply : forall P Q:Prop, P -> (P->Q) -> Q.
Proof.
  intros P Q p pq.
  apply pq.
  apply p.
Qed.

(* 2/25 auto *)
(*
   Coq は簡単な証明は自動的に証明してくれる機能が幾つかありますが、
   auto はよく使われます。autoが何をやっているか知りたい場合は、
   autoの代わりにinfo autoと入力すると、autoの中で何をしてるかが判ります。
   Coqの初学者にはinfoは便利ですよ。
*)

Lemma Sample_of_auto : forall A B:Prop, ((((A->B)->A)->A)->B)->B.
Proof.
  info auto.
Qed.

(* 3/25 rewrite *)
(*
   rewrite は仮定にある等式を使ってゴールを書き換えます。
   下記の例では、リスト xs について帰納法を用いて証明していますが、
   ゴールの中に含まれるlength (xs ++ ys)を、
   帰納法の仮定IHxsを用いてrewriteすることでlength xs + length ysに書き換えています。
*)

Require Import List.
Lemma Sample_of_rewrite : forall (A:Set)(xs ys:list A),
  length (xs ++ ys) = length xs + length ys.
Proof.
  intros A xs ys.
  induction xs.
  reflexivity.
  simpl.
  rewrite IHxs.
  reflexivity.
Qed.

(* 4/25 destruct *)
(*
   destruct は基本的にはある項を場合分けする時使うのですが、
   仮定の中にある /\ とか \/ とか exists とかを分解するのに使うのに便利です。
   （それ以外のときは induction とか case_eq とか使う事が多い様にも思います。）
   下記の例では仮定 abc を分解して仮定 a, b, c を作っています。
*)

Lemma Sample_of_destruct : forall A B C:Prop,
  A /\ (B /\ C) -> (A /\ B) /\ C.
Proof.
  intros A B C abc.
  destruct abc as (a, (b, c)).
  split; [ split | idtac ]; assumption.
Qed.

(* 5/25 intros *)
(*
   実は過去４回の記事でも毎回 intros を使用していました。
   forall とかで定義された変数や -> の左の式とかを仮定に持って行く為に使います。
   introの複数形なので、introを必要な回数繰り返してもOKです。
   intros. だけでも勝手に適当に名前（仮定は通常 H? みたいな名前）を付けてくれますが、
   判りやすさを考えると自分で適切な名前を付けた方が良いと思います。
*)

Lemma Sample_of_intros : forall A B C:Prop, (A->B->C) -> (A->B) -> A -> C.
Proof.
  intros A B C abc ab a.
  apply abc.
  exact a.
  apply ab; exact a.
Qed.

(* 6/25 omega *)
(*
   Coq でよく使われる tactic の６つ目は omega です...
   ってanarchy proofは課題が数学寄りに偏っているから、
   順序が６つ目というのはあまり気にしないで下さい。
   omega タクティックは、
   forallとかexistsとかを含まない形のPresburger算術の式を自動証明してくれます。
   端的に言うと、

   ・割り算無し。
   ・変数と変数の掛け算が入っていない。
   ・変数と定数（2, 3などの具体的な整数）の掛け算はOK。

   みたいな感じの等式 or 不等式を証明します。
   Coqがよく使われる理由は、この手の数式関係の自動証明が便利に使えるからだと思います。
   整数の等式不等式に関する公理定理を組み合わせて証明するとか大変ですからね。

   簡単な例はこんなのです。
   使い方は簡単で、Require Import Omega して、introsとかして、omega と入力するだけ。
*)

Require Import Omega.
Lemma Sample_of_omega : forall x:nat, x > 1 -> 3 * x > x + 2.
Proof.
  intros.
  info omega.
Qed.

(* 7/25 assert *)
(*
   １つ目のapplyのところで書いた様に、Coqの証明は最初にゴールがあって、
   それを仮定と逆に戻して行く格好になっています。
   しかし証明する人間は仮定からゴールを考える方が楽な場合、
   つまり証明途中で適当な補題を作りたくなる場合があります。
   補題はある程度汎用性があるならば、予め切り出して証明しておいた方が良いと思いますが、
   使い捨て的な補題は assert を使うと、証明内証明みたいに作る事ができます。
   例えば下記の例で、
*)
Lemma Sample_of_assert : forall P Q, (P /\ P) -> (Q /\ Q) -> (P /\ Q).
Proof.
  intros P Q pp qq.
(*
   ここまで証明した段階で、forall X, X /\ X -> Xという補題があれば、
   ppからPを、qqからQを取り出せて便利そうだと考えました。
   そこでassertを使います。すると現在の証明課題より先に、
   まずこの補題が証明課題になります。
*)
  assert(H: forall X, X /\ X -> X).
  intros X xx.
  destruct xx as [x _].
  exact x.
(*
   assertで設定した補題 H の証明が終わると、以後は仮定 H としてそれを使う事が出来ます。
*)
  split.
  apply (H P).
  exact pp.
  apply (H Q).
  exact qq.
Qed.

(* 8/25 intro *)
(*
   基本的には前に説明したintrosと同じで、introsと違って一度に１つしかintro出来ないのが違います。
   あと、introsと違ってintroの場合は、
   ~Pの形のゴールを、Pという仮定と、Falseというゴールに変形出来ます。
   ~PはP->Falseなのですが、intros.では~Pは~Pのままです。
*)

Lemma Sample_of_intro : forall P, ~~~P -> ~P.
Proof.
  intro P.
  intro nnnp.
  intro p.
  elim nnnp.
  intro np.
  elim np.
  exact p.
Qed.

(* 9/25 simpl *)
(*
   simpl はβι簡約(beta, iota)をして式を簡単にします。
   βι簡約が何かについては「言語ゲーム」の記事が判りやすいです。
   β簡約は関数適用で、ι簡約だと再帰的に関数が適用される、と考えると良いです。

   予め、足し算の定義を示しておきます。plus を含んだ式を simpl すると、
   一つ目の変数 n について再帰的にパターンマッチして式を変形してくれます。
*)
Print plus.
(* 足し算を使った simpl の使用例です。 *)
Lemma Sample_of_simpl : forall n m, n + m = m + n.
Proof.
  intros n m.
  induction n.
  simpl.
(*
   simpl を使うと左辺の0 + mがnに簡約されますが、右辺は変化がありません。
   ここは別途証明しておいた（というか標準ライブラリにはいっている）
   定理のplus_n_Oを使って書き換える事にします。
*)
  Check plus_n_O.
  erewrite <- plus_n_O.
  reflexivity.

(* 帰納法の後半も simpl を使い、別の補題plus_n_Smを使います。*)
  Check plus_n_Sm.
  erewrite <- plus_n_Sm.
  erewrite <- IHn.
  reflexivity.
Qed.

(* 10/25 unfold *)
(*
   unfold は関数定義を展開します。
   unfold だけで使う場合も有りますが、fold と組み合わせて使う事もあります。
   fold は展開された関数を元に戻します。
   unfold して、simpl とか rewrite とかして、
   また fold して戻すと式が良い具合に変形されている場合があります。
   ここではそういう例を見てみましょう。
*)
(* まず、sum n := 1 + 2 + ... + nという関数を定義します。*)

Fixpoint sum n :=
  match n with
    | O => O
    | S n' => S n' + sum n'
  end.

(*
   次に、sum n = 1/2 * n * (n + 1) であることを証明したいのですが、
   割り算が入ると面倒ですから、次の定理を証明する事にします。
   今回は環に関する自動証明器の ring を使いたいのでArithとRingをImportしておきます。
   nに関する帰納法で、n=0の場合はさらっと証明を流すことにします。
*)
Require Import Arith Ring.
Lemma Sample_of_unfold : forall n, 2 * sum n = n * (n + 1).
Proof.
  induction n.
  reflexivity.
  (*
     ここで、sum を unfold して、fold すると式が少し変形されます。
     *)
  unfold sum.
  fold sum.
  (*
     ここでreplaceを使ってちょっと左辺を書き換えます。書き換えて良い証明はsubgoal 2と後回しです。
     *)
  replace (2 * (S n + sum n)) with (2 * S n + 2 * sum n).
  (*
     ここでIHnを用いて書き換えて式変形を ring で自動証明します。後回しにしたものもringで一発です。
     *)
  rewrite IHn.
  ring.
  ring.
Qed.

(* 11/25 exists *)
(*
   証明のゴールが exists x, P x とか { n:nat | isPrime n } とか、
   ある性質を満たす要素が存在することを求めている時に、
   「具体的に」その要素を与えてゴールを変形します。

   下記は exists を使う簡単な例です。
   mの具体的な値としてS n = n+1 を与えています。
   具体的なmを何か与えないとomegaでの自動証明は通りません。
*)

Lemma Sample_of_exists : forall n, exists m, n < m.
Proof.
  intros.
  exists (S n).
  omega.
Qed.

(* 12/25 replace *)
(*
   Coq でよく使われる tactic の12番目は replace です。
   replace t1 with t2 とすると、t2 = t1 という等式をsubgoalに追加し、
   t2 = t1 を用いてゴールの書き換えを行います。
   書き換え規則 t2 = t1 の証明を先送りにすることで本筋の証明の見通しがよくなります。
   また、simpl, unfold, rewriteを使う場合とかで、
   「ゴールのこの部分だけ書き換えたいのだが別のところも書き換えられてしまう」
   と悩む場面もありますが、
   そういうときは replace でとりあえず部分的に書き換え、
   あとでその箇所の書き換えを証明すると楽です。
   replace を多用するのは、等式変形を繰り返す場合です。今回はそういう例を。
*)

(* 下記の様に群 G を定義してみます。 *)

Axiom G : Set.                                           (* 群G *)
Axiom G_dec : forall a b:G, {a=b} + {a <> b}.            (* 単位元や逆元の一意性とかを示す時に必要 *)
Axiom mult : G -> G -> G.                                (* 乗法 *)
Notation "a * b" := (mult a b).                          (* 記号 * で書ける様にする *)
Axiom assoc : forall a b c:G, (a * b) * c = a * (b * c). (* 結合則 *)
Axiom G1 : G.                                            (* 単位元 *)
Notation "1" := G1.                                      (* 記号 1 で書ける様にする *)
Axiom id_l : forall a:G, 1 * a = a.                      (* 左単位元である *)
Axiom inv : G -> G.                                      (* 逆元 *)
Axiom inv_l : forall a:G, (inv a) * a = 1.               (* 左逆元 *)

(*
   では、左逆元は右逆元でもあることを証明してみます。
   長くなるのでゴールを示すのは要所要所だけです。
   replaceを使うと、subgoalが増えているのが判ります。
*)

Theorem inv_r : forall a:G, a * (inv a) = 1.
Proof.
  intros.
  replace (a * inv a) with (1 * a * inv a) .
  replace (1 * a * inv a) with (inv (inv a) * inv a * a * inv a) .
  replace (inv (inv a) * inv a * a * inv a) with
    (inv (inv a) * (inv a * a) * inv a) .
  rewrite inv_l.                            (* ここからは replace を使わなくても
                                               rewrite で簡単に変形出来る *)
  rewrite assoc.
  rewrite id_l.
  rewrite inv_l.
  reflexivity.                              (* メインゴールの証明完了。
                                               残りは replace の書き換えの証明 *)
  rewrite <- assoc; reflexivity.
  erewrite inv_l; reflexivity.
  rewrite assoc; rewrite id_l; reflexivity.
Qed.

(* 13/25 induction *)
(*
   Coq は帰納的な型を定義すると、その型に対する帰納法を自動で定義してくれます。
   例えば

   Inductive nat : Set :=
   | O : nat
   | S : nat -> nat.

   という自然数natに対して、

   forall P : nat -> Prop,
   P 0 ->
   (forall n : nat, P n -> P (S n)) ->
   forall n : nat, P n

   というnat_indを定義してくれます。
   これを使って、自然数nについての帰納法の証明の時に、

   ・n=0 の場合のゴール
   ・nの時成り立つという仮定IHnと、S nの場合のゴール

   を作ってくれます。同様にリストであれば、nilとconsの場合などです。
   今までにも何度か induction を使った証明を示してきましたが、今回も簡単な例を。
*)

Lemma plus_comm : forall n m, n + m = m + n.
Proof.
  induction n.
  intro m.
  simpl.
  erewrite <- plus_n_O.
  reflexivity.
  intro m.
  simpl.
  erewrite <- plus_n_Sm.
  erewrite IHn.
  reflexivity.
Qed.

(* 14/25 split *)
(*
   split はゴールが P /\ Q の形をしている時に、
   二つのゴール P, Q に分割します。あとはそれぞれを別々に証明すればOKです。
*)

Lemma Sample_of_split : forall A B C:Prop, A /\ (B /\ C) -> (A /\ B) /\ C.
Proof.
  intros A B C abc.
  destruct abc as [a [b c]].
  split.
  split.
  assumption.
  assumption.
  assumption.
Qed.

(* 15/25 case *)
(*
   帰納的な型について自動で場合分けをしてくれるという意味では、13番目のinductionと同じですが、
   inductionと違って単に場合分けを行うだけで帰納法の仮定とかは作ってくれません。

   今回は３値論理を定義してみます。帰納的な bool3 という型を定義し、
   それらに対する否定、論理積、論理和を定義します。
*)
Inductive bool3 : Set := yes | maybe | no.
Definition not3(b:bool3) :=
  match b with
    | yes => no
    | maybe => maybe
    | no => yes
  end.

Definition and3(a b:bool3) :=
  match a,b with
    | yes,yes => yes
    | no, _ => no
    | _, no => no
    | _,_ => maybe
  end.

Definition or3(a b:bool3) :=
  match a,b with
    | no,no => no
    | yes,_ => yes
    | _,yes => yes
    | _,_ => maybe
  end.

(*
   では、bool3 における簡単な証明をしてみます。
   a, b についての場合分けを行うのに case タクティックを使用します。
   下記の例では case でゴールが増えるのを示したいので個別に case を使っていますが、
   普通は、
   case a; case b; reflexivity.
   で一行で９通りの場合分けを実施して終了とするでしょう。
*)
Lemma Sample_of_case : forall a b:bool3,
  not3 (or3 a b) = and3 (not3 a) (not3 b).
Proof.
  intros a b.
  case a.
  case b.
  reflexivity.
  reflexivity.
  reflexivity.
  case b; reflexivity.
  case b; reflexivity.
Qed.

(* 16/25 ring *)
(*
   ring は可換な半環（演算 +, * があって、それぞれ単位元 0, 1 があって、
   それぞれ交換則と結合則が成り立って、分配法則があってな数学的構造）
   での計算を行ってくれます。
   基本的には多項式の掛け算を展開し、標準形に直して比較するようなことをします。
   使用するにはRequire Import Ring.が必要です。
   下記で色々試してみましたが、適宜 rewrite, replace なども併用しないとうまくいきませんでした。
*)

Require Import ZArith Ring.
Open Scope Z_scope.
Lemma Sample_of_ring : forall a b:Z, a + b = 7 -> a * b = 12 -> a^2 + b^2 = 25.
Proof.
  intros a b H1 H2.
  replace (a^2 + b^2) with ((a+b)^2 - 2*a*b) by ring.
  rewrite H1.
  replace (2*a*b) with (2*12) by ring [H2].
  reflexivity.
Qed.
Close Scope Z_scope.

(* 17/25 elim *)
(*
   elim はほとんど induction と同じ事が出来ます。
   例えばこんな感じ。帰納法の仮定を自分で intro する必要があるのが違います。
*)

Lemma Sample_of_elim : forall n, n + 0 = n.
Proof.
  intros.
  elim n.
Abort.

(*
   ただこうやって帰納法で使うときはinductionする方が多い様にも思います。
   下記の様にゴールが False で、仮定が ~P の形をしている時は、
   私は習慣で他のタクティックではなく elim を使います。こんな感じ。
   *)

Lemma Sample_of_elim' : forall P, ~~(P \/ ~P).
Proof.
  intros.
  intro npnp.
  elim npnp.
  right.
  intro p.
  elim npnp.
  left.
  exact p.
Qed.

(* 18/25 clear *)
(*
   clear Hとすると、仮定 H が消えます。下記の様な感じです。
*)

Lemma Sample_of_clear : forall A B C, (A->B->C)->(A->B)->A->C.
Proof.
  intros A B C abc ab a.
  apply abc; clear abc.
  exact a.
  apply ab; clear ab.
  exact a.
Qed.

(*
   使い終わって不要になった仮定をclearで消すと多少見通しが良くなる事もありますが、
   あまり使わないのではないかなぁ。
   むしろ、各種 tactic の中で内部的に使われる事が多い様な気がします。
   例えば下記の簡単な tactic の swap の中で使われています。
   apply して一回使った仮定は不要なので clear で消しているようです。
*)

Ltac swap H :=
  idtac "swap is OBSOLETE: use contradict instead.";
  intro; apply H; clear H.

(* これを使った証明です。*)

Lemma Sample_of_claer : forall P, ~~~P -> ~P.
Proof.
  intros.
  swap H.
  swap ipattern:H.
  exact H0.
Qed.

(* 19/25 inversion *)
(*
   inversion は仮定に対して帰納的な定義を適用し、その仮定が成立する為の前提を導き出すか、
   あるいはそもそもそのような前提が存在しない（＝仮定が間違っている）ので証明終了、
   を導いてくれます。
   ある種の証明では inversion を使うと証明が非常に簡単なのですが、
   中で何をしているのかは簡単には説明するのは難しいです。
*)

(* inversionの使用例というと典型的にはこの関数を定義することになっています。*)
Inductive even : nat -> Prop :=
| EvenO : even O
| EvenSS : forall n, even n -> even (S (S n)).

(*
   偶数である事を、上記の様に帰納的に定義します。
   では３が偶数でない事を証明しましょう。
   こういう定理の証明の時にはinversionが有用です。
   今回はinversionの中で何をしているかみたいのでinfo inversionとして使っています。
*)

Lemma Sample_of_inversion : ~(even 3).
Proof.
  intro.
  info inversion H.
(* H: even 3の前提にH1: even 1が前提である事が判りました。
   このH1について再度inversionを使います。 *)
  info inversion H1.
Qed.
(* H1を成立させる前提が無いので、証明完了になります。*)

(* あと、inversionが役に立つ例というとsmall-stepの決定性の証明とかです。*)
Inductive term : Set :=
| TmTrue : term
| TmFalse : term
| TmIf : term -> term -> term -> term.

Inductive eval : term -> term -> Prop :=
| EvIfTrue : forall t2 t3, eval (TmIf TmTrue t2 t3) t2
| EvIfFalse : forall t2 t3, eval (TmIf TmFalse t2 t3) t3
| EvIf : forall t1 t1' t2 t3, eval t1 t1' ->
  eval (TmIf t1 t2 t3) (TmIf t1' t2 t3).

(* 上記の様にsmall-stepの規則を定義して、下記を証明します。*)

Theorem eval_deterministic : forall t t' t'', (eval t t') -> (eval t t'') -> (t' = t'').
Proof.
  intros t t' t'' tEt' tEt''.

  (* まず tEt' について induction で場合分けをします。*)
  induction tEt' as [t2 t3|t2 t3|t1 t1' t2 t3 t1Et1'] in t'', tEt'' |-*.
  (*
     最初の場合は、t' = TmIf TmTrue t2 t3 の場合です。
     ここで tEt'' については induction ではなくinversion を使うと、
     tEt'' が成立するような t'' の場合分けを自動で行ってくれます。
     *)
  inversion tEt'' as [t2_ t3_| t2_ t3_| t1_ t1'_ t2_ t3_ t1Et1'_].
  reflexivity.
  (*
     ここでinversion t1Et1'_を行います。
     TmTrueが何かにevalされる規則はevalに無いので、仮定が不成立となり、
     goalの証明が終わります。
     *)
  inversion t1Et1'_.

  (* t' = TmIfFalse t2 t3 の場合は同様の証明をすればOKです。*)
  inversion tEt'' as [t2_ t3_| t2_ t3_| t1_ t1'_ t2_ t3_ t1Et1'_].
  reflexivity.
  inversion t1Et1'_.

  (*
     最後は、t' = TmIf t1 t2 t3 の場合についてです。
     やはりtEt''についてinversionします。
     *)
  inversion tEt'' as [t2_ t3_| t2_ t3_| t1_ t1'_ t2_ t3_ t1Et1'_].
  (*
   ここでも、H0とt1Et1'から、eval TmTrue t1'を作って
   inversionして仮定が成立しない事を使って証明します。
   *)
  rewrite <- H0 in t1Et1'.
  inversion t1Et1'.

  (* 同様にして、TmFalse の場合も証明出来ます。*)
  rewrite <- H0 in t1Et1'.
  inversion t1Et1'.

  (* 最後はIHt1Et1'のt''をt1'_にして、t1Et1'_と組み合わせてゴールを導きます。*)
  rewrite (IHt1Et1' t1'_ t1Et1'_).
  reflexivity.
Qed.

(* 20/25 generalize *)
(*
   generalize は intro の逆で、具体的な値の term を、"forall t" のような形に戻します。
   簡単な使用例は下記の様なものです。
*)
Lemma sample_of_generalize : forall x y, 0 <= x + y + y.
Proof.
  intros.
  generalize (x + y + y).
  Require Import Arith.Le.
  apply le_O_n.
Qed.

(*
   単純に generalize で戻せない場合は、generalize dependent t のような形で使います。
   例えば下記の証明（TAPLの練習問題の証明）で使っています。
   よほど明らかな場合以外は、generalize dependentの形で使う事が多い様に思います。
   まず証明の前提の定義を幾つか。
*)
Inductive term2 : Set :=
| Tm2True : term2
| Tm2False : term2
| Tm2If : term2 -> term2 -> term2 -> term2
| Tm2Zero : term2
| Tm2Succ : term2 -> term2
| Tm2Pred : term2 -> term2
| Tm2Iszero : term2 -> term2.

Inductive nvalue : term2 -> Prop :=
| NvZero : nvalue Tm2Zero
| NvSucc : forall t, nvalue t -> nvalue (Tm2Succ t).

Inductive bvalue : term2 -> Prop :=
| BvTrue : bvalue Tm2True
| BvFalse : bvalue Tm2False.

Definition value(t:term2) : Prop := bvalue t \/ nvalue t.

Inductive eval2 : term2 -> term2 -> Prop :=
| Ev2IfTrue : forall t2 t3, eval2 (Tm2If Tm2True t2 t3) t2
| Ev2IfFalse : forall t2 t3, eval2 (Tm2If Tm2False t2 t3) t3
| Ev2If : forall t1 t1' t2 t3, eval2 t1 t1' -> eval2 (Tm2If t1 t2 t3) (Tm2If t1' t2 t3)
| Ev2Succ : forall t1 t1', eval2 t1 t1' -> eval2 (Tm2Succ t1) (Tm2Succ t1')
| Ev2Pred : forall t1 t1', eval2 t1 t1' -> eval2 (Tm2Pred t1) (Tm2Pred t1')
| Ev2PredZero : eval2 (Tm2Pred Tm2Zero) Tm2Zero
| Ev2PredSucc : forall nv, nvalue nv -> eval2 (Tm2Pred (Tm2Succ nv)) nv
| Ev2IszeroZero : eval2 (Tm2Iszero Tm2Zero) Tm2True
| Ev2IszeroSucc : forall nv, nvalue nv -> eval2 (Tm2Iszero (Tm2Succ nv)) Tm2False
| Ev2Iszero : forall t1 t1', eval2 t1 t1' -> eval2 (Tm2Iszero t1) (Tm2Iszero t1').

Notation "t1 ---> t2" := (eval2 t1 t2) (at level 80, no associativity).

Definition normal_form (t : term2) : Prop := ~ exists t', eval2 t t'.

(* ここで下記の定理を証明します。
   intros を下記の様にすると予めdestructした形で intros 可能です。
*)
Lemma value_is_normal_form : forall v, value v -> normal_form v.
Proof.
  intros v [bv|nv] [t vEt].
  destruct bv; inversion vEt.
(*
   ここで t をgeneralize dependentします。
   （generalize t だと、forall t:term2, にならずうまくいかない。）
*)
  generalize dependent t.
  induction nv.
  intros t zEt.
  inversion zEt.
  intros t0 stEt0.
  inversion stEt0.
  elim (IHnv t1').
  exact H0.
Qed.

(* 21,22/25 left, right *)
(*
   left は constructor 1 、right は constructor 2 の意味で、
   実は goal が A \/ B の場合に限らず、
   コンストラクタが２通りあってどちらかを明示的に指定したい時に使えます。
   大抵そういう場合は左右と対応している訳ですが、例えば nat とかも left が O を指すはず。
   同様に n:nat に対して destruct n ではなく split とかも使えるはず。
   単に他人に判りにくいだけですが。

   今回は sumbool について left, right を使う例です。やはり左右に対応しています。
*)
Lemma Sample_of_left_right : forall n:nat, {n = 0} + {n <> 0}.
Proof.
  induction n.
  left.
  reflexivity.

  right.
  intro.
  inversion H.
Qed.

(* 23/25 specialize *)
(*
   公理とかライブラリにある定理とか証明済み補題とかに、
   特定の引数を適用した物を仮定に使いたい事があります。
   forall n, P n. みたいな補題Lのnに特定の値 n0 を代入した P n0 が仮定にあると良いなぁ、とか。
   勿論、assert(H:P n0)とかcut (P n0)とか書いても良いのですが、
   specialize (L n0). と書けば cut (P n0)してapply (L n0) するのと同じになり、
   証明が短く判りやすくなります。

   replaceの説明の時と同じ定理を、replaceを使わず、specializeとrewriteを使って証明してみます。
   証明の前提と成る公理は replace の回を参照して下さい。
*)
Theorem inv_r' : forall a:G, a * (inv a) = 1.
Proof.
  intros.
  specialize (id_l (a * inv a)).
  (*
     specializeすると、公理 id_l に (a * inv a) を適用した物が得られますので、
     intro して書き換えて消去します。あとは同様に。
     *)
  intro H; rewrite <- H; clear H.
  specialize (inv_l (inv a)); intro H; rewrite <- H; clear H.
  specialize (assoc (inv (inv a)) (inv a) (a * inv a)); intro H; rewrite H; clear H.
  specialize (assoc (inv a) a (inv a)); intro H; rewrite <- H; clear H.
  specialize (inv_l a); intro H; rewrite H; clear H.
  specialize (id_l (inv a)); intro H; rewrite H; clear H.
  reflexivity.
Qed.

(* 24/25 exact *)
(*
   現在のゴールが、仮定のどれか、あるいは既存の定理にマッチする時に
   exact H?. とか exact my_theorem. とかするとゴールが証明されます。
   前者の場合は assumption. で済みますし、
   exact ではなく apply でもOKなんで、無理に使う必要は無いですが、
   ゴールと同じ物があったという意図を多少は示せるのかも。
   exact を使って書いてみました。
*)

Lemma Sample_of_exact : forall n m, n + m = m + n.
Proof.
  intros.
  induction n.
  simpl.
  exact (plus_n_O m).
  simpl.
  rewrite IHn.
  exact (plus_n_Sm m n).
Qed.

(* 25/25 reflexivity *)
(*
   reflexivity はゴールが等式で、左辺と右辺の値が等しい時に使います。
   内容的には apply refl_equal. と同じです。refl_equal はこんな公理。

Inductive eq (A : Type) (x : A) : A -> Prop :=  refl_equal : x = x.

   左辺と右辺が全く同じ形をしていないと等式は成り立ちません
   （が、reflexivity は内部的に simpl を実行しているので
   simpl で簡単化して等しくなる物は成立します）。

   ところで、同じ形というのはどこまで同じならば = が成り立つかというのは良く解らないので、
   色々試してみました。
*)

Definition f : nat -> nat := fun x => x.
Definition h : nat -> nat := fun y => y .
Goal f = h.
  simpl.
  unfold f.
  unfold h.
  reflexivity.
Qed.
(*
   これを見ると、(fun x : nat => x) = (fun y : nat => y) は成立するようです。同様に、
*)

Goal forall P:nat->Prop, (forall n, P n) = (forall m, P m).
  intros P.
  reflexivity.
Qed.
(*
   これを見ると、(forall n : nat, P n) = (forall m : nat, P m) も成立。
   上記の f, h の場合はreflexivityで等しい事が示せましたが、
   一般には関数が等しい事を reflexivity で証明する事は出来ません。

   f, g : nat -> nat について、f = g ⇔ ∀n:nat, f n = g n. を以て等しいとする場合は、
   こんな感じで証明します。
*)

Definition f' : nat -> nat := fun x => x.
Fixpoint g' (x:nat) : nat :=
  match x with
    | O => O
    | S n' => S (g' n')
  end.

Require Import Logic.FunctionalExtensionality.

Lemma Sample_of_reflexivity : f' = g'.
Proof.
  extensionality n.
  unfold f'.
  induction n.
  reflexivity.
  simpl.
  rewrite <- IHn.
  reflexivity.
Qed.

(*
   他にも、= を同値関係を以て定義する場合は Setoid というものを使って考える
   （Coqの型理論には集合論の商集合が無いので、代わりに = を同値関係で置き換えた物を使う）
   とか有るらしいのですが、そっちはちょっと調べきれませんでした。
*)

(* END *)


Require Import Bool Arith List Cpdt.CpdtTactics.
Set Implicit Arguments.
Set Asymmetric Patterns.

Inductive even_list : Set :=
| ENil : even_list
| ECons : nat -> odd_list -> even_list

with odd_list : Set :=
| OCons : nat -> even_list -> odd_list.

Fixpoint elength  (el : even_list) : nat :=
  match el with
  | ENil => O
  | ECons _ ol => S (olength ol)
  end

with olength (ol : odd_list) : nat :=
       match ol with
       | OCons _ el => S (elength el)
       end.

Fixpoint eapp (el1 el2 : even_list) : even_list :=
  match el1 with
  | ENil => el2
  | ECons n ol => ECons n (oapp ol el2)
  end

with oapp (ol : odd_list) (el : even_list) : odd_list :=
       match ol with
       | OCons n el' => OCons n (eapp el' el)
       end.

Theorem elength_app : forall el1 el2 : even_list,
    elength (eapp el1 el2) = plus (elength el1) (elength el2).
  induction el1; crush.
Abort.

Check even_list_ind.

Scheme even_list_mut := Induction for even_list Sort Prop
  with odd_list_mut := Induction for odd_list Sort Prop.

Check even_list_mut.

Theorem elength_eapp : forall el1 el2 : even_list,
    elength (eapp el1 el2) = plus (elength el1) (elength el2).

  apply (even_list_mut
           (fun el1 : even_list => forall el2 : even_list,
                elength (eapp el1 el2) = plus (elength el1) (elength el2))
           (fun ol : odd_list => forall el : even_list,
                olength (oapp ol el) = plus (olength ol) (elength el))); crush.
  Qed.


Require Import Nat.

Inductive lst : Type :=
  | Nil : lst
  | Cons : nat -> lst -> lst.

Fixpoint len (l : lst) : nat :=
  match l with
  | Nil => 0
  | Cons x y => 1 + len y
  end.

Fixpoint append (l1 : lst) (l2 : lst) : lst :=
  match l1 with
  | Nil => l2
  | Cons x y => Cons x (append y l2)
  end.

Fixpoint rev (l : lst) : lst :=
  match l with
  | Nil => Nil
  | Cons x y => append (rev y) (Cons x Nil)
  end.

Lemma len_append : forall x y : lst, len (append x y) = len x + len y.
Proof.
  intros.
  induction x.
  - reflexivity.
  - simpl. rewrite IHx. reflexivity.
Qed.

Theorem len_rev : forall x : lst, len (rev x) = len x.
Proof.
  intros.
  induction x.
  - reflexivity.
  - simpl.
    rewrite len_append.
    rewrite IHx.
    simpl.
    rewrite <- plus_n_Sm.
    auto.
Qed.


Require Import List.
Require Import Arith.
Require Import Bool.
From Coq Require Import ssreflect ssrfun ssrbool.
From mathcomp Require Import eqtype ssrnat div prime.
(*Imports, check "lib" folder.*)

(*Inductive nat : Set :=
| O : nat
| S : nat -> nat.*)

Print nat.

Eval compute in 0.
Eval compute in S(O). (*1*)

Fixpoint add(a b :nat) : nat :=
  match a with
  | 0 => b
  | S n => S(add n b)
end.

Compute add 1 3.

Theorem add_assoc : forall (a b c : nat),
  (add a (add b c)) = (add (add a b) c).
Proof. (*Begin proof*)
  intros a b c. (*Introduce a b c as "given".*)
  induction a as [|n].  (*Induction on a, as n.*)
    simpl. reflexivity. (*Base case*)
    simpl. rewrite -> IHn. reflexivity. (*General case*)
Qed. (*Begin proof*)

Print add_assoc.

Print nat_ind.

Theorem one_not_eq_two : ~ 1 = 2.
Proof.
unfold not.
intros H.
inversion H.
Qed.

Theorem n_geq_zero : ~ 0 > 0.
Proof.
unfold not. unfold gt. unfold lt.
intros H.
inversion H.
Qed.

Definition pred (n : nat) : n > 0 -> nat :=
  match n with
  | O => fun pf => match (n_geq_zero pf) with end
  | S n' => fun _ => n'
end.

Theorem one_exists : exists (n : nat), n = 1.
Proof.
exists 1. reflexivity.
Qed.

Eval compute in pred 3.

Notation "x | y" := (y mod x = 0)
(at level 50, left associativity).


Require Import Coq.ZArith.ZArith.
Require Import riscv.util.div_mod_to_quot_rem.
Require Import Coq.micromega.Lia.

Local Open Scope Z_scope.

Definition bitSlice(x: Z)(start eend: Z): Z :=
  Z.land (Z.shiftr x start) (Z.lnot (Z.shiftl (-1) (eend - start))).

Definition signExtend(l: Z)(n: Z): Z :=
  if Z.testbit n (l-1) then (n - (Z.setbit 0 l)) else n.

Definition bitSlice'(w start eend: Z): Z :=
  (w / 2 ^ start) mod (2 ^ (eend - start)).

Lemma bitSlice_alt: forall w start eend,
    0 <= start <= eend ->
    bitSlice w start eend = bitSlice' w start eend.
Proof.
  intros. unfold bitSlice, bitSlice'.
  rewrite <- Z.land_ones by omega.
  rewrite <- Z.shiftr_div_pow2 by omega.
  f_equal.
  rewrite Z.shiftl_mul_pow2 by omega.
  rewrite Z.mul_comm.
  rewrite <- Z.opp_eq_mul_m1.
  replace (Z.lnot (- 2 ^ (eend - start))) with (2 ^ (eend - start) - 1).
  - rewrite Z.ones_equiv. reflexivity.
  - pose proof (Z.add_lnot_diag (- 2 ^ (eend - start))). omega.
Qed.

Lemma bitSlice_range: forall sz z,
    0 <= sz ->
    0 <= bitSlice z 0 sz < 2 ^ sz.
Proof.
  intros.
  rewrite bitSlice_alt by omega.
  unfold bitSlice'.
  change (2 ^ 0) with 1.
  rewrite Z.div_1_r.
  rewrite Z.sub_0_r.
  apply Z.mod_pos_bound.
  apply Z.pow_pos_nonneg; omega.
Qed.

Lemma bitSlice_split: forall sz1 sz2 v,
    (0 <= sz1)%Z ->
    (0 <= sz2)%Z ->
    (bitSlice v sz1 (sz1 + sz2) * 2 ^ sz1 + bitSlice v 0 sz1)%Z = bitSlice v 0 (sz1 + sz2).
Proof.
  intros. rewrite? bitSlice_alt by omega. unfold bitSlice'.
  change (2 ^ 0)%Z with 1%Z.
  rewrite Z.div_1_r.
  rewrite! Z.sub_0_r.
  replace (sz1 + sz2 - sz1)%Z with sz2 by omega.
  rewrite Z.pow_add_r by assumption.
  assert (0 < 2 ^ sz1)%Z by (apply Z.pow_pos_nonneg; omega).
  assert (0 < 2 ^ sz2)%Z by (apply Z.pow_pos_nonneg; omega).
  rewrite Z.rem_mul_r by omega.
  nia.
Qed.

Definition signExtend'(l n: Z): Z := n - ((n / 2 ^ (l - 1)) mod 2) * 2 ^ l.

Lemma signExtend_alt: forall l n,
    0 < l ->
    signExtend l n = signExtend' l n.
Proof.
  intros. unfold signExtend, signExtend'.
  destruct (Z.testbit n (l - 1)) eqn: E.
  - apply (f_equal Z.b2z) in E.
    rewrite Z.testbit_spec' in E by omega.
    rewrite E.
    rewrite Z.setbit_spec'.
    rewrite Z.lor_0_l.
    change (Z.b2z true) with 1.
    rewrite Z.mul_1_l.
    reflexivity.
  - apply (f_equal Z.b2z) in E.
    rewrite Z.testbit_spec' in E by omega.
    rewrite E.
    change (Z.b2z false) with 0.
    rewrite Z.mul_0_l.
    rewrite Z.sub_0_r.
    reflexivity.
Qed.

Lemma mul_div2_undo_mod: forall a, 2 * (a / 2) = a - a mod 2.
Proof.
  intros.
  pose proof (Z.div_mod a 2).
  omega.
Qed.

Lemma or_to_plus: forall a b,
    Z.land a b = 0 ->
    Z.lor a b = a + b.
Proof.
  intros.
  rewrite <- Z.lxor_lor by assumption.
  symmetry. apply Z.add_nocarry_lxor. assumption.
Qed.

Definition signExtend_alt': forall l n,
    0 < l ->
    (exists q, n / 2 ^ (l - 1) = 2 * q /\ signExtend l n = n) \/
    (exists q, n / 2 ^ (l - 1) = 2 * q + 1 /\ signExtend l n = n - 2 ^ l).
Proof.
  intros. rewrite signExtend_alt by assumption. unfold signExtend'.
  pose proof (Z.mod_pos_bound (n / 2 ^ (l - 1)) 2).
  assert ((n / 2 ^ (l - 1)) mod 2 = 0 \/ (n / 2 ^ (l - 1)) mod 2 = 1) as C by omega.
  destruct C as [C | C]; rewrite C.
  - left. exists (n / 2 ^ (l - 1) / 2). rewrite mul_div2_undo_mod. omega.
  - right. exists (n / 2 ^ (l - 1) / 2). rewrite mul_div2_undo_mod. omega.
Qed.

Definition signExtend2(l n: Z): Z :=
  if Z.testbit n (l - 1) then Z.lor n (Z.shiftl (-1) l) else n.

Lemma signExtend_alt2: forall l n,
    0 < l ->
    Z.land (Z.shiftl (-1) l) n = 0 ->
    signExtend l n = signExtend2 l n.
Proof.
  intros.
  unfold signExtend, signExtend2.
  destruct (Z.testbit n (l - 1)) eqn: E; [|reflexivity].
  rewrite <- Z.add_opp_r.
  pose proof (Z.add_lnot_diag (Z.setbit 0 l)).
  replace (- (Z.setbit 0 l)) with (Z.lnot (Z.setbit 0 l) + 1) by omega.
  replace (Z.lnot (Z.setbit 0 l) + 1) with (Z.shiftl (-1) l).
  - symmetry. apply or_to_plus. rewrite Z.land_comm. assumption.
  - replace (Z.lnot (Z.setbit 0 l)) with (- Z.setbit 0 l - 1) by omega.
    rewrite Z.shiftl_mul_pow2 by omega.
    rewrite Z.setbit_spec'.
    rewrite Z.lor_0_l.
    omega.
Qed.

Lemma bitSlice_all_nonneg: forall n v : Z,
    (0 <= n)%Z ->
    (0 <= v < 2 ^ n)%Z ->
    bitSlice v 0 n = v.
Proof.
  clear. intros.
  rewrite bitSlice_alt by omega.
  unfold bitSlice'.
  change (2 ^ 0)%Z with 1%Z.
  rewrite Z.div_1_r.
  rewrite Z.sub_0_r.
  apply Z.mod_small.
  assumption.
Qed.

Lemma bitSlice_all_neg: forall n v : Z,
    (0 <= n)%Z ->
    (- 2 ^ n <= v < 0)%Z ->
    bitSlice v 0 n = (2 ^ n + v)%Z.
Proof.
  clear. intros.
  rewrite bitSlice_alt by omega.
  unfold bitSlice'.
  change (2 ^ 0)%Z with 1%Z.
  rewrite Z.div_1_r.
  rewrite Z.sub_0_r.
  assert (0 < 2 ^ n)%Z. {
    apply Z.pow_pos_nonneg; omega.
  }
  div_mod_to_quot_rem.
  subst v.
  rewrite Z.add_assoc.
  assert (q = -1)%Z by nia.
  subst q.
  nia.
Qed.


Require Export TopologicalSpaces.
Require Export OpenBases.
Require Export FiniteTypes.
Require Export EnsemblesSpec.

Section Subbasis.

Variable X:TopologicalSpace.
Variable SB:Family (point_set X).

Record subbasis : Prop := {
  subbasis_elements: forall U:Ensemble (point_set X),
    In SB U -> open U;
  subbasis_cover: forall (U:Ensemble (point_set X)) (x:point_set X),
    In U x -> open U ->
    exists A:Type, FiniteT A /\
    exists V:A->Ensemble (point_set X),
      (forall a:A, In SB (V a)) /\
      In (IndexedIntersection V) x /\
      Included (IndexedIntersection V) U
}.

Lemma open_basis_is_subbasis: open_basis SB -> subbasis.
Proof.
intros.
destruct H.
constructor.
exact open_basis_elements.
intros.
destruct (open_basis_cover x U); trivial.
destruct H1 as [? [? ?]].
exists True.
split.
apply True_finite.
exists (True_rect x0).
repeat split; intros.
destruct a.
simpl.
assumption.
destruct a.
simpl.
assumption.
red; intros.
destruct H4.
apply H2.
exact (H4 I).
Qed.

Lemma finite_intersections_of_subbasis_form_open_basis:
  subbasis ->
  open_basis [ U:Ensemble (point_set X) |
              exists A:Type, FiniteT A /\
              exists V:A->Ensemble (point_set X),
              (forall a:A, In SB (V a)) /\
              U = IndexedIntersection V ].
Proof.
constructor.
intros.
destruct H0.
destruct H0 as [A [? [V' [? ?]]]].
rewrite H2.
apply open_finite_indexed_intersection; trivial.
intros.
apply H; trivial.

intros.
pose proof (subbasis_cover H U x).
destruct H2 as [A [? [V [? [? ?]]]]]; trivial.
exists (IndexedIntersection V).
repeat split; trivial.
exists A; split; trivial.
exists V; trivial.
split; trivial.
destruct H4.
exact H4.
Qed.

End Subbasis.

Arguments subbasis [X].

Section build_from_subbasis.

Variable X:Type.
Variable S:Family X.

Require Import FiniteIntersections.

Definition Build_TopologicalSpace_from_subbasis : TopologicalSpace.
refine (Build_TopologicalSpace_from_open_basis
  (finite_intersections S) _ _).
red; intros.
exists (Intersection U V); repeat split; trivial.
apply intro_intersection; trivial.
destruct H1; assumption.
destruct H1; assumption.
destruct H2; assumption.
destruct H2; assumption.

red; intro.
exists Full_set.
split; constructor.
Defined.

Lemma Build_TopologicalSpace_from_subbasis_subbasis:
  @subbasis Build_TopologicalSpace_from_subbasis S.
Proof.
assert (@open_basis Build_TopologicalSpace_from_subbasis
  (finite_intersections S)).
apply Build_TopologicalSpace_from_open_basis_basis.
constructor.
intros.
simpl in U.
apply open_basis_elements with (finite_intersections S); trivial.
constructor; trivial.

intros.
destruct (@open_basis_cover _ _ H x U) as [V]; trivial.
destruct H2 as [? [? ?]].
simpl.

pose proof (finite_intersection_is_finite_indexed_intersection
  _ _ H2).
destruct H5 as [A [? [W [? ?]]]].
exists A; split; trivial.
exists W; repeat split; trivial.

rewrite H7 in H4; destruct H4; apply H4.
rewrite H7 in H3; assumption.
Qed.

End build_from_subbasis.