I'm trying to prove the first example in "Practical Coinduction" in Coq. The first example is to prove that lexicographical ordering on infinite streams of integers is transitive.
I haven't been able to formulate the proof to get around the Guardedness condition
Here is my development so far. First just the usual definition of infinite streams. Then definition of lexicographical order called lex
. And in the end the failed proof of the transitivity theorem.
Require Import Omega.
Section stream.
Variable A:Set.
CoInductive Stream : Set :=
| Cons : A -> Stream -> Stream.
Definition head (s : Stream) :=
match s with Cons a s' => a end.
Definition tail (s : Stream) :=
match s with Cons a s' => s' end.
Lemma cons_ht: forall s, Cons (head s) (tail s) = s.
intros. destruct s. reflexivity. Qed.
End stream.
Implicit Arguments Cons [A].
Implicit Arguments head [A].
Implicit Arguments tail [A].
Implicit Arguments cons_ht [A].
CoInductive lex s1 s2 : Prop :=
is_le : head s1 <= head s2 ->
(head s1 = head s2 -> lex (tail s1) (tail s2)) ->
lex s1 s2.
Lemma lex_helper: forall s1 s2,
head s1 = head s2 ->
lex (Cons (head s1) (tail s1)) (Cons (head s2) (tail s2)) ->
lex (tail s1) (tail s2).
Proof. intros; inversion H0; auto. Qed.
Here is the lemma I want to prove. I start by preparing the goal so I can apply a constructor, hoping to eventually be able to use the "hypothesis" from cofix
.
Lemma lex_lemma : forall s1 s2 s3, lex s1 s2 -> lex s2 s3 -> lex s1 s3.
intros s1 s2 s3 lex12 lex23.
cofix.
rewrite <- (cons_ht s1).
rewrite <- (cons_ht s3).
assert (head s1 <= head s3) by (inversion lex12; inversion lex23; omega).
apply is_le; auto.
simpl; intros. inversion lex12; inversion lex23.
assert (head s2 = head s1) by omega.
rewrite <- H0, H5 in *.
assert (lex (tail s1) (tail s2)) by (auto).
assert (lex (tail s2) (tail s3)) by (auto).
apply lex_helper.
auto.
repeat rewrite cons_ht.
Guarded.
How do I proceed from here? Thanks for any hints!
- EDIT
Thanks to Arthur's (as always!) helpful and enlightening answer I too could complete the proof. I give my version below for reference.
Lemma lex_lemma : forall s1 s2 s3, lex s1 s2 -> lex s2 s3 -> lex s1 s3.
cofix.
intros s1 s2 s3 lex12 lex23.
inversion lex12; inversion lex23.
rewrite <- (cons_ht s1).
rewrite <- (cons_ht s3).
constructor; simpl.
inversion lex12; inversion lex23; omega.
intros; eapply lex_lemma; [apply H0 | apply H2]; omega.
Qed.
I use the cons_ht
lemma to "expand" the value of s1
and s3
. The definition of lex
here (with head
and tail
) is more close to the verbatim formulation in Practical Coinduction. Arthur uses a more elegant technique which makes Coq expand the values automatically - much nicer!