Module Exploration1.
(** With bogus subtraction, this omega_example1 theorem even True? Yes it is; let's try again, the hard way, to find the proof. *)
(** And here's the easy way. *)
(** Here we have used the [omega] tactic, made available by importing [Coq.omega.Omega] as we have done above.  Omega is an algorithm for integer linear programming, invented in 1991 by William Pugh. Because ILP is NP-complete, we might expect that this algorithm is exponential-time in the worst case, and indeed that's true: if you have [N] equations, it could take [2^N] time.  But in the typical cases that result from reasoning about programs, omega is much faster than that.  Coq's [omega] tactic is an implementation of this algorithm that generates a machine-checkable Coq proof.  It "understands" the types Z and nat, and these operators: [<] [=] [>] [<=] [>=] [+] [-] [~], as well as multiplication by small integer literals (such as 0,1,2,3...) and some uses of [\/] and [/\].  Omega does _not_ understand other operators.  It treats things like [a*b] and [f x y] as if they were variables.  That is, it can prove [f x y > a*b -> f x y + 3 >= a*b], in the same way it would prove [u > v -> u+3 >= v].  Now let's consider a silly little program: swap the first two elements of a list, if they are out of order. *)
Definition maybe_swap (al: list nat) : list nat :=
match al with
| a :: b :: ar => if a >? b then b::a::ar else a::b::ar
| _ => al
end.
Example maybe_swap_123:
maybe_swap [1; 2; 3] = [1; 2; 3].
(** Moral of this story: When proving things about a program that uses boolean comparisons [(a <? b)], use [bdestruct].  Then use [omega].  Let's review that proof without all the comments. *)
(* ################################################################# *)
(** * Permutations *)
(** Another useful fact about [maybe_swap] is that it doesn't add or remove elements from the list: it only reorders them.  We can say that the output list is a _permutation_ of the input.  The Coq [Permutation] library has an inductive definition of permutations, along with some lemmas about them. *)
Locate Permutation. (* Inductive Coq.Sorting.Permutation.Permutation *)
Check Permutation. (*  : forall {A : Type}, list A -> list A -> Prop *)
(** We say "list [al] is a permutation of list [bl]", written [Permutation al bl], if the elements of [al] can be reordered (without insertions or deletions) to get the list [bl]. *)
Print Permutation.
(* Inductive Permutation {A : Type} : list A -> list A -> Prop := perm_nil : Permutation [] [] | perm_skip : forall (x : A) (l l' : list A), Permutation l l' -> Permutation (x :: l) (x :: l') | perm_swap : forall (x y : A) (l : list A), Permutation (y :: x :: l) (x :: y :: l) | perm_trans : forall l l' l'' : list A, Permutation l l' -> Permutation l' l'' -> Permutation l l''. *)
(** You might wonder, "is that really the right definition?"  And indeed, it's important that we get a right definition, because [Permutation] is going to be used in the specification of correctness of our searching and sorting algorithms.  If we have the wrong specification, then all our proofs of "correctness" will be useless.  It's not obvious that this is indeed the right specification of permutations. (It happens to be true, but it's not obvious!)  In order to gain confidence that we have the right specification, we should use this specification to prove some properties that we think permutations ought to have. *)
(** **** Exercise: 2 stars (Permutation_properties)  *)
(** Think of some properties of the [Permutation] relation and write them down informally in English, or a mix of Coq and English. Here are four to get you started: - 1. If [Permutation al bl], then [length al = length bl]. - 2. If [Permutation al bl], then [Permutation bl al]. - 3. [[1;1]] is NOT a permutation of [[1;2]]. - 4. [[1;2;3;4]] IS a permutation of [[3;4;2;1]].  YOUR ASSIGNMENT: Add three more properties. Write them here: *)
(** Now, let's examine all the theorems in the Coq library about permutations: *)
Search Permutation.  (* Browse through the results of this query! *)
(** Which of the properties that you wrote down above have already been proved as theorems by the Coq library developers?  Answer here:  *)
(** [] *)
(** Let's use the permutation rules in the library to prove the following theorem. *)
Example butterfly: forall b u t e r f l y : nat,
Permutation ([b;u;t;t;e;r]++[f;l;y]) ([f;l;u;t;t;e;r]++[b;y]).
(** That example illustrates a general method for proving permutations involving cons [::] and append [++]. You identify some portion appearing in both sides; you bring that portion to the front on each side using lemmas such as [Permutation_app_comm] and [perm_swap], with generous use of [perm_trans].  Then, you use [perm_skip] to cancel a single element, or [Permutation_app_head] to cancel an append-chunk. *)
(** **** Exercise: 3 stars (permut_example)  *)
(** Use the permutation rules in the library (see the [Search], above) to prove the following theorem.  These [Check] commands are a hint about what lemmas you'll need. *)
Check perm_skip.
Check Permutation_refl.
Check Permutation_app_comm.
Check app_assoc.
Example permut_example: forall (a b: list nat),
Permutation (5::6::a++b) ((5::b)++(6::a++[])).
(** Now let us specify functional correctness of [maybe_swap]: it rearranges the elements in such a way that the first is less-or-equal than the second. *)
Definition first_le_second (al: list nat) : Prop :=
match al with
| a::b::_ => a <= b
| _ => True
end.

Theorem maybe_swap_correct: forall al,
Permutation al (maybe_swap al)
/\ first_le_second (maybe_swap al).