(** printing \2/ $\cup$ #&cup;# *)
(** printing <2= $\subseteq$ #&sube;# *)
(** printing forall $\forall$ #&forall;# *)
(** printing -> $\rightarrow$ #&rarr;# *)
(** printing /\ $\land$ #&and;# *)
(** * Illustrating the [paco] library  This tutorial shows how to use our [paco] library to reason about coinductive predicates in Coq.  By coinductive predicates we mean objects that one can define using [CoInductive] and whose type ends in [Prop].  The library implements _parameterized coinduction_, as described in our draft paper entitled #<a href=" http://plv.mpi-sws.org/paco/"># _The Power of Parameterization in Coinductive Proof_ #</a>#.  How does parameterized coinduction compare to Coq's existing support for coinductive proofs?  For proofs by _induction_, Coq provides a tactic called [fix], but proofs done directly with [fix] are required to satisfy a _syntactic guardedness_ criterion.  Fortunately, Coq also generates induction _lemmas_ for every inductive definition, which eliminate the need to ever use the low-level [fix] tactic and worry about guardedness.  For proofs by coinduction, Coq provides a tactic [cofix] analogous to [fix], i.e., also based on a syntactic guardedness criterion.  However, Coq does not generate any lemmas for coinductive definitions.  Consequently, to reason about such definitions, the user must use the low-level [cofix] tactic.  Due to its syntactic nature, [cofix] is problematic in several ways (please see the paper linked above for detailed discussion of these points):  - It is non-compositional. - It is inefficient. - It is not user-friendly. - It interacts poorly with builtin automation tactics.   The [paco] library provides a tactic, [pcofix], which can be seen as a replacement for Coq's builtin [cofix] tactic (in the case of predicates) that does not involve any syntactic guardedness criterion and thus avoids all of these problems.  In addition, like Coq's [cofix], [pcofix] provides built-in support for _incremental_ proofs, i.e., proofs in which the coinduction hypothesis is extended gradually as the proof progresses.  We believe this combination of compositionality, incrementality, robustness, and ease of use makes [pcofix] a superior alternative to [cofix] for proofs about coinductive predicates.  The rest of this tutorial illustrates the use of the [paco] library with the help of three examples. *)(* *)
(** ** Example: stream equality  The first example involves streams of natural numbers and an equality thereon.  We prove a particular equality via [cofix], and then explain how that proof can be turned into one via [pcofix]. *)
(** We start by defining a type of streams of natural numbers. *)
CoInductive stream :=
| cons : nat -> stream -> stream.
(** The following, seemingly useless, lemma is a common trick for working with corecursive terms such as our streams.  (It will be used in the example proofs.)  For details, see for instance #<a href="http://adam.chlipala.net/cpdt/html/Coinductive.html">Adam Chlipala's book on Certified Programming with Dependent Types</a>#. *)
Definition sunf s :=
match s with cons n s' => cons n s' end.
(** In order to state our example equality, we define an enumeration stream and a map operation for streams. *)
CoFixpoint enumerate n : stream :=
cons n (enumerate (S n)).
CoFixpoint map f s : stream :=
match s with cons n s' => cons (f n) (map f s') end.
(** *** A proof using [cofix]  We will now prove, using [cofix], that for any [n] the stream [enumerate n] is equal to the stream [cons n (map S (enumerate n))]. *)
(** First, we define an equality [seq] on streams.  Usually, one would do this as follows.  [CoInductive seq : stream -> stream -> Prop :=] #<br># [  | seq_fold : forall n s1 s2 (R : seq s1 s2), seq (cons n s1) (cons n s2).]  Instead, we define the generating function, [seq_gen], beforehand, and then define [seq] as its greatest fixed point using [CoInductive].  The reason is simply that we need [seq_gen] later when using [paco].  If applying parameterized coinduction to an existing development where the generating function is not explicit, it can always easily be made explicit.  Note that, albeit the use of [Inductive], the definition of [seq_gen] is not recursive. *)
Inductive seq_gen seq : stream -> stream -> Prop :=
| _seq_gen : forall n s1 s2 (R : seq s1 s2 : Prop), seq_gen seq (cons n s1) (cons n s2).
Hint Constructors seq_gen.
CoInductive seq : stream -> stream -> Prop :=
| seq_fold : forall s1 s2, seq_gen seq s1 s2 -> seq s1 s2.
(** Second, we do the actual proof. *)
(** _Note_: One might want to eliminate the use of [pattern] in the proof script by replacing the corresponding line with the following:  [rewrite sunf_eq at 1; simpl.]  However, doing so will result in an invalid proof (rejected at [Qed]-time).  The reason is that the proof term created by [rewrite] ... [at 1] involves some lemmas from the [Setoid] library.  Like most lemmas, these are opaque, so guardedness checking cannot inspect their proofs and thus fails.  This is a great example of two of the previously mentioned problems with the [cofix] approach, namely lack of compositionality and poor interaction with standard tactics. *)(* *)
(** *** A proof using our [pcofix]  We will now do the same proof, but using the [paco] library.  We first simply show the new (but equivalent) definition of stream equality and the new proof of the example, and then explain what is going on behind the scenes.  In both, we use [paco] constructs with suffix "2" because we are dealing with predicates of arity 2 here.  _Note_: [Paco] supports predicates of arity up to 8.  Also, it supports up to three mutually coinductive predicates (see the last example of this tutorial).  In either case, extending this is just a matter of copy and paste.  We also have to prove monotonicity of the generating function [seq_gen], which can be discharged by the tactic [pmonauto], and register it in the Hint databse [paco].  _Remark_: Unlike [CoInductive], [paco] does not care whether the generating function is given in a _strictly positive_ syntactic form; all that matters is that the function is monotone. More specifically, [paco2 f] is well defined for an arbitrary generating function [f] regardless of whether it is monotone or not. However, in order to ensure that [paco2 f bot2] is the greatest fixed point of [f], we need monotonicity of [f]. *)
Definition seq' s1 s2 := paco2 seq_gen bot2 s1 s2.
Hint Unfold seq'.
Hint Resolve seq_gen_mon : paco.

Theorem example' : forall n, seq' (enumerate n) (cons n (map S (enumerate n))).