(** printing \2/ $\cup$ #&cup;# *)
(** printing <2= $\subseteq$ #&sube;# *)
(** printing forall $\forall$ #&forall;# *)
(** printing -> $\rightarrow$ #&rarr;# *)
(** printing /\ $\land$ #&and;# *)
Set Implicit Arguments.
Set Contextual Implicit.
(** * A Mixed Induction-Coinduction Example  Written by Steve Zdancewic. *)
CoInductive stream (A:Type) :=
| snil : stream A
| scons : A -> stream A -> stream A
.
Arguments scons {_} _ _.
Definition id_match_stream {A} (s:stream A) : stream A :=
match s with
| snil => snil
| scons x t => scons x t
end.
(* A more relaxed notion of equivalence where the 0's can be inserted finitely often in either stream. *)
Inductive seq_step (seq : stream nat -> stream nat -> Prop) : stream nat -> stream nat -> Prop :=
| seq_nil  : seq_step seq snil snil
| seq_cons : forall s1 s2 n (R : seq s1 s2), seq_step seq (scons n s1) (scons n s2)
| seq_cons_z_l : forall s1 s2, seq_step seq s1 s2 -> seq_step seq (scons 0 s1) s2
| seq_cons_z_r : forall s1 s2, seq_step seq s1 s2 -> seq_step seq s1 (scons 0 s2)
.
Hint Constructors seq_step : core.
Hint Resolve seq_step_mono : paco.
Definition seq (s t : stream nat) := paco2 seq_step bot2 s t .
Hint Unfold seq : core.
Inductive zeros_star (P: stream nat -> Prop) : stream nat -> Prop :=
| zs_base t (BASE: P t): zeros_star P t
| zs_step t (LZ: zeros_star P t): zeros_star P (scons 0 t)
.
Hint Constructors zeros_star : core.
Hint Resolve zeros_star_mono : core.
Inductive zeros_one (P: stream nat -> Prop) : stream nat -> Prop :=
| zo_step t (BASE: P t): zeros_one P (scons 0 t)
.
Hint Constructors zeros_one : core.
Hint Resolve zeros_one_mono : paco.
Definition infzeros := paco1 zeros_one bot1.
Hint Unfold infzeros : core.
Inductive nonzero: stream nat -> Prop :=
| nz_nil: nonzero snil
| nz_cons n s (NZ: n <> 0): nonzero (scons n s)
.
Hint Constructors nonzero : core.
Inductive gseq_cons_or_nil (gseq: stream nat -> stream nat -> Prop) : stream nat -> stream nat -> Prop :=
| gseq_nil : gseq_cons_or_nil gseq snil snil
| gseq_cons s1 s2 n (R: gseq s1 s2) (NZ: n <> 0) : gseq_cons_or_nil gseq (scons n s1) (scons n s2)
.
Hint Constructors gseq_cons_or_nil : core.
Inductive gseq_step (gseq: stream nat -> stream nat -> Prop) : stream nat -> stream nat -> Prop :=
| gseq_inf s1 s2 (IZ1: infzeros s1) (IZ2: infzeros s2) : gseq_step gseq s1 s2
| gseq_fin s1 s2 t1 t2
(ZS1: zeros_star (fun t => t = s1) t1)
(ZS2: zeros_star (fun t => t = s2) t2)
(R: gseq_cons_or_nil gseq s1 s2)
: gseq_step gseq t1 t2
.
Hint Constructors gseq_step : core.
Hint Resolve gseq_step_mono : paco.
Definition gseq (s t : stream nat) := paco2 gseq_step bot2 s t .
Hint Unfold gseq : core.

Lemma infzeros_or_finzeros: forall s,
infzeros s \/ zeros_star nonzero s.