(** * Proving with computer assistance, Spring 2010 *)
(* Version of 25/3/2010 *)


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

(** The main PA for this course is the Coq proof assistant.  

    Coq can be seen as a combination of:
      - a simple but still very expressive functional programming language,
      - a language for defining abstract and concrete mathematical concepts,
      - a language for writing logical formulas expressing properties of 
        mathematical concepts or assertions of programs 
      - a language and a set of tools for proving these formulas

    The Coq system has fairly few things "built in", but there is a
    standard library which contains basic things like booleans,
    numbers and lists. Also there are many user contributions around
    on the web. Also, Coq provides powerful tools for defining your
    own types and functions and for constructing your own proof
    tactics. *)

(* ###################################################################### *)
(** * Working with Coq *)

(** Coq is a free program available via the site 
    http://coq.inria.fr. There are compiled binary versions 
    for Linux and Windows.
 
    For this practicum it is recommended that you install Coq
    IDE or ProofGeneral or that you use the prover system:
    http://prover.cs.ru.nl
 
    For getting a login for the course (and teh prover system) and in
    general for more information, look at:
    http://www.cs.ru.nl/H.Geuvers/onderwijs/provingwithCA/
 
 *)



Section Introduction.
(** 
   Using the command Goal we enter the proof mode and set the
   proposition that we will try to prove.
*)

Goal forall A B C: Prop, (A -> B -> C) -> (A -> B) -> (A -> C).
intros.
apply H.
assumption.
apply H0.
assumption.
(**  
  The proof is now complete. It can be saved for future use 
 with the command Save, followed by a name for the new
 theorem. This also ends the proof mode.
*)
Save Tautology1.

(**  
  To prove and save the result above, we could also have 
 stated it as a Theorem or Lemma, as follows: 
*)

Lemma Tautology1': 
forall A B C:Prop, (A -> B -> C) -> (A -> B) -> (A -> C).
Proof.
intros.
apply H.
assumption.
apply H0.
assumption.
Qed.

(** 
  NB "tauto" just finishes the proof right away;
     it is a complete tautology checker for constructive 
     propositional logic

  NB "Admitted" leaves the proof without finishing it;
     this can be useful if you first want to prove something else

  With Qed. the proof is validated and added to the environment. 
  In fact this method is usually preferred unless we do not
 want to give a name to a proof.
*)

(**
 The natural numbers are pre-defined in Coq as
> nat: Set
 Check that with the command
> Check nat.
  The terms "O" and "S" represent the natural number zero 
 and the successor function (adding of 1). Check their 
 types with the Check command.
*)
Check nat.
Check O.
Check S.

(** 
  The function that adds two to its argument can be defined as: 
*)
Definition Add_two := fun x:nat => S (S x).

(** But also, the number two can be defined as *)
Definition two := 2.
(** 
  We could have also used "S (S 0)" in place of "2", they are
 equivalent
*)

(** Now two can be used in the definition of the function: *)

Definition Add_two' (x: nat) := x + two.

(**  
  Note the parameter in the definition. This is a syntactic
 sugar and a more readable way of writing:
> Definition Add_two'' := fun x: nat => x + two.
*)

(**
  One example on how the notion of equality can be introduced
 in Coq. (Note: Coq has already a built-in equality denoted by
 the symbol "=", but in this example we define our own).
*)
Variable IS : forall A: Set, A -> A -> Prop.

(** 
  The line above only defines "IS" as a binary relation on an 
 arbitrary set "A" - this is a polymorphic equality. 
 Reflexivity can be introduced by an extra axiom:
*)
Axiom refl: forall (A: Set) (z: A), IS A z z.

(** 
  Now we should be able to prove "IS nat (Add_two O) two" and 
 indeed  this is the case as shown below  
*)

Goal (IS nat (Add_two O) two).
apply refl.
Qed.

Goal (IS nat (Add_two' O) two).
apply refl.
Qed.

(** 
  What happened here? Coq can see that 
 "IS nat (Add_two' O) two)" is an instance of the reflexivity 
 axiom "IS A z z". It takes "nat" for the set "A" and "two" for
 "z", but "two" is (by definition) equal to 
 "Add_two' O". This check is performed automatically as 
 follows:

Add_two' O =                    (By unfolding Add_two)
0 + two =                       (By beta-reduction)
two

   Hence, when comparing two terms, Coq folds or unfolds 
 definitions as necessary 
*)

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

(** * Classical Logic in Coq *)

(** 
  This example shows how we can do classical logic in Coq

  Suppose we want to prove that for all propositions "A" and "B" 
 the following holds: "(~A -> B) -> (~B -> A)".
  Note that negation is defined as
> Definition not (A: Prop) := A -> False
 and "~A" is an abbreviation for "not A".
  Let us give this proposition the name contra (from
 contraposition): 
*)
Print not.

Definition contra := forall A B: Prop, (~A -> B) -> (~B -> A).
Print contra.

(**  
  You can try to prove contra using the tauto or the intuition 
 tactic:

> Goal contra.

> tauto.

  Unfortunately, Coq cannot prove contra with the tactic 
 tauto or intuition, because it is not provable in the
 constructive logic of Coq. To prove this proposition, we
 need the axiom for double negation: 
*)
Hypothesis classical: forall A: Prop, ~~A -> A.

(** With this extra axiom we can prove contra *)

Goal contra.
unfold contra.
intros.
apply classical.
(* 
 The goal at this moment is

  A : Prop

  B : Prop

  H : ~A->B

  H0 : ~B

  ===================

  ~~A

 Remember the definition of "not"? "~~A" can also be written 
  as "~A -> False", so...
*)

intro.

(*
 This results in the following goal:

  A : Prop

  B : Prop

  H : ~A->B

  H0 : ~B

  H1 : ~A

  ===================

  False

 In this context, from "H" and "H1" we can obtain a proof of 
"B" and since H0 is a proof of "~B" (i.e. "B -> False"), we 
will get False. However, Coq always works in a backwards 
manner, we need to use first "H0" (and then the goal will be to 
prove "B"). Next, to prove "B", we will need to use "H" (and 
the goal will become "~A"). The final step will be trivial, 
because "H1" is a proof of "~A".
*)

apply H0.

(*

  A : Prop

  B : Prop

  H : ~A->B

  H0 : ~B

  H1 : ~A

  ===================

  B
*)
apply H.

(*

  A : Prop

  B : Prop

  H : ~A->B

  H0 : ~B

  H1 : ~A

  ===================

  ~A
*)

assumption.

(** To see the proof-term that we created, use Show Proof: *)
Show Proof.

(**
> Proof: fun (A B: Prop)(H: ~A -> B)(H0: ~B) =>
>    classical A (fun H1: ~A => H0 (H H1))

  Although we prove a formula in classical logic, you can still
 use the automated tactics of Coq. They will work for subgoals
 that do not require the axiom "classical"
*)
Qed.

(** 
  The part with the worked-out examples ends here. Now you can 
 try to prove the exercises below yourself.
*)

End Introduction.

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

(** *** Exercise 1. (implications)  *)

(** Prove the following propositions: 

So you have to replace all the Admitted by real Coq proofs.
*)
Lemma L1_1: forall p q r: Prop, 
  (p -> q) -> (q -> r) -> (p -> r).
Admitted.

Lemma L1_2: forall p q: Prop, (p -> p -> q) -> (p -> q).
Admitted.

Lemma L1_3: forall p q: Prop, (p -> q) -> (p -> p -> q).
Admitted.

Lemma L1_4: forall p q r:Prop, (p -> q -> r) -> (q -> p -> r).
Admitted.

(* ###################################################################### *)
(** *** Exercise 2. (falsum)  *)

(**
 Define "false" as follows: 
*)
Definition false := forall p: Prop, p.
Check false.

(** 
  Prove that from "false" follows any other proposition, 
 i.e. prove the following 
*)
Lemma ex_falso: forall p:Prop, false -> p.
Admitted.

(** Prove the following propositions: *)

Lemma L2_1: forall p q: Prop, (p -> q) -> ~q -> ~p.
Admitted.

Lemma L2_2: forall p: Prop, p -> ~~p.
Admitted.

Lemma L2_3: forall p: Prop, ~~~p -> ~p.
Admitted.

(* ###################################################################### *)
(** *** Exercise 3. *)

(** 
 Introduce the following axiom 
*)

Axiom classical: forall p: Prop, ~~p -> p.

(** Using it prove: *)

Lemma L3_1: forall p q: Prop, (~q -> ~p) -> (p -> q).
Admitted.

(** 
  For the following lemma you may want need to use the tactic:
> absurd X
  that changes the present goal to two subgoals: "X" and "~X".

   You may find this lemma difficult to prove - if so then
 skip it and do not spend too much time on it.
*)
Lemma L3_2: forall p q: Prop, ((p -> q) -> p) -> p.
Admitted.

(* ###################################################################### *)
(** *** Exercise 4. (conjunction) *)

(**  Define conjunction by 
*)

Definition AND (p q:Prop) := 
  forall (a: Prop), (p -> q -> a)->a.

Check AND.

Lemma projl: forall p q: Prop, AND p q -> p.
Admitted.

Lemma projr: forall p q: Prop, AND p q -> q.
Admitted.

Lemma pair:  forall p q: Prop, p -> q -> AND p q.
Admitted.

(** 
  Note: Coq defines conjunction and disjunction in a different
 way than the one we are using here. More information on this 
 can be found in the Coq tutorial (see the Coq homepage) 
*)

(* ###################################################################### *)
(** *** Exercise 5. (disjunction) *)

(** Define disjunction as follows 
*)

Definition OR (p q: Prop) := forall (a: Prop), 
 (p -> a) -> (q -> a) -> a.
Check OR.

(** Prove the following tautologies: *)

Lemma inl: forall p q: Prop, p -> OR p q.
Admitted.

Lemma inr: forall p q: Prop, q -> OR p q.
Admitted.

(* ###################################################################### *)
(** *** Exercise 6. (more junctions) *)

(**  Prove the following using the lemmas proved in Exercise 4
 and 5: 
*)

Lemma L6_1: forall p q: Prop, AND p q -> OR q p.
Admitted.

Lemma L6_2: forall p q: Prop, AND p q -> AND q p.
Admitted.

Lemma L6_3: forall p q r: Prop, OR (OR p q) r -> OR p (OR q r).
Admitted.

(* ###################################################################### *)
(** *** Exercise 7 (Inductive types) *)

(**
 Define the type of the finite lists of natural numbers: 
*)

Inductive List: Set :=
 | nil: List
 | cons: nat -> List -> List.

(** 
  Coq defines automatically the corresponding induction 
 principle: 
*)
Check List_ind.

(** 
  Hence we can prove properties of lists of natural numbers 
 by induction. Furthermore, we can define functions with 
 recursion: 
*)

(** Length of a list, defined by pattern matching. *)
Fixpoint Len (L: List) : nat :=
 match L with
 | nil => O
 | cons l ls => S (Len ls)
 end.

(** 
  Appending two lists.
  For recursive definitions to be well-defined one of the 
 arguments must be decreasing (becoming smaller in the 
 recursive call to ensure that the recursion will terminate). 
 If there is more than one parameter we must inform Coq which
 one is decreasing by the "struct" keyword.
*)
Fixpoint Append (L R: List) {struct L} : List :=
 match L with
 | nil => R
 | cons l ls => cons l (Append ls R)
end.

Print Append.

(** Prove the following: *)

Lemma Len_nil: Len nil = O.
Admitted.

Lemma Len_Append: forall L R: List, 
  Len (Append L R) = Len L + Len R.
Admitted.

(** 
  We define a function Reverse that given a list returns 
 another list with the elements of the first in reverse order 
*)

Fixpoint Reverse (L: List) : List :=
 match L with
 | nil => nil 
 | cons l ls => Append (Reverse ls) (cons l nil)
 end.

Lemma Reverse_nil: Reverse nil = nil.
Admitted.

Lemma Reverse_two_elts: forall a b: nat, 
 Reverse (cons a (cons b nil))= cons b (cons a nil).
Admitted.

(** 
  In the following lemma you may need to use the commutativity
 of plus. This result is present in Coq standard library
 together with plenty of other results.
 See: http://coq.inria.fr/library-eng.html

  Libraries can be loaded using "Require Import" command.
*)
Require Import Arith.
(**
  You can search for all results concerning plus (or any other 
 definition) with the following command:
*)
SearchAbout plus.
(**
  The lemma stating commutativity of plus is called "plus_comm"
*)
Check plus_comm.

(** 
  Prove that Reverse returns a list of the same size as 
 its argument 
*)
Lemma Reverse_Len: forall L: List, Len (Reverse L) = Len L.
Admitted.

(** 
  Prove that if we apply Reverse two times we get back the 
 original list. For that you may need a number of auxiliary 
 lemmas, like: associativity of Append
*)
Lemma Append_assoc: forall L R T: List, 
 Append (Append L R) T = Append L (Append R T).
Admitted.

(**
  ... appending with an empty list as second argument
*)
Lemma Append_nil: forall L: List, Append L nil = L.
Admitted.

(**
 ... and distributivity of Reverse with Append
*)
Lemma Reverse_Append: forall L R: List, 
 Reverse (Append L R) = Append (Reverse R) (Reverse L).
Admitted.

(**
 Finally: double Reverse
*)
Lemma Reverse_twice: forall L: List, L = Reverse (Reverse L).
Admitted.

(* ###################################################################### *)
(** * Naive Set Theory *)
(** *** Exercise 8. (naive set representation) *)

(**
 Introduce a variable U of type Set.: 
*)

Variable U: Set.

(** 
   We can think of the predicates on "U" as sets, i.e. "U" is the 
 'universe' of all objects and a set is a predicate that describes
 which of the elements of the universe belong to it. If "A" is of 
 type "U -> Prop" then "A" can be seen as the set {x:U | A(x)}, 
 the elements of U for which the predicate holds. Hence we define
*)
Definition SET := U -> Prop.

(** 
  If "A: SET" and "x: U" then "A x" means `x is an element of A'. 
*)

(** 1. Define the subset relation on SET. *)
Definition subset (P Q: SET) := forall x: U, P x -> Q x.
Check subset.

(** 2. Prove that subset is reflexive and transitive *)
Lemma subset_refl: forall A: SET, subset A A.
Admitted.

Lemma subset_trans: forall A B C: SET, 
 subset A B -> subset B C -> subset A C.
Admitted.

(** 
  3. Using subset, define equality, union and intersection of 
 SETs. Note that "/\" is Coq notation for conjunction and "\/"
 for disjunction.
*)
Definition eq_set (A B: SET) := subset A B /\ subset B A.
Definition union (A B: SET) := fun x:U => A x \/ B x.
Definition intersection (A B: SET) := fun x:U => A x /\ B x.

(** 4. Prove *)
Lemma intersection_subset: forall A B: SET,
  subset (intersection A B) A.
Admitted.

Lemma subset_union: forall A B: SET,
  subset A (union A B).
Admitted.

Lemma union_double: forall A: SET, eq_set (union A A) A.
Admitted.

(** 
  5. Define the empty set and prove that it is a subset of every 
 other SET. 
*)
Definition empty := fun x:U => False.

Lemma empty_subset: forall A: SET, subset empty A.
Admitted.
