Section CLOSURES.
Variable genv: Type.
Variable state: Type.
(** A one-step transition relation has the following signature. It is parameterized by a global environment, which does not change during the transition.  It relates the initial state of the transition with its final state.  The [trace] parameter captures the observable events possibly generated during the transition. *)
Variable step: state -> trace -> state -> Prop.
(** No transitions: stuck state *)
Definition nostep (s: state) : Prop :=
forall t s', ~(step s t s').
(** Zero, one or several transitions.  Also known as Kleene closure, or reflexive transitive closure. *)
Inductive star : state -> trace -> state -> Prop :=
| star_refl: forall s,
star s E0 s
| star_step: forall s1 t1 s2 t2 s3 t,
step s1 t1 s2 -> star s2 t2 s3 -> t = t1 ** t2 ->
star s1 t s3.
Proof star_step.
(** One or several transitions.  Also known as the transitive closure. *)
Inductive plus : state -> trace -> state -> Prop :=
| plus_left: forall s1 t1 s2 t2 s3 t,
step s1 t1 s2 -> star s2 t2 s3 -> t = t1 ** t2 ->
plus s1 t s3.
(** Counted sequences of transitions *)
Inductive starN : nat -> state -> trace -> state -> Prop :=
| starN_refl: forall s,
starN O s E0 s
| starN_step: forall n s t t1 s' t2 s'',
step s t1 s' -> starN n s' t2 s'' -> t = t1 ** t2 ->
starN (S n) s t s''.
Remark starN_star:
forall n s t s', starN n s t s' -> star s t s'.
Remark star_starN:
forall s t s', star s t s' -> exists n, starN n s t s'.
(** Infinitely many transitions *)
CoInductive forever : state -> traceinf -> Prop :=
| forever_intro: forall s1 t s2 T,
step s1 t s2 -> forever s2 T ->
forever s1 (t *** T).
(** An alternate, equivalent definition of [forever] that is useful for coinductive reasoning. *)
Variable A: Type.
Variable order: A -> A -> Prop.
CoInductive forever_N : A -> state -> traceinf -> Prop :=
| forever_N_star: forall s1 t s2 a1 a2 T1 T2,
star s1 t s2 ->
order a2 a1 ->
forever_N a2 s2 T2 ->
T1 = t *** T2 ->
forever_N a1 s1 T1
| forever_N_plus: forall s1 t s2 a1 a2 T1 T2,
plus s1 t s2 ->
forever_N a2 s2 T2 ->
T1 = t *** T2 ->
forever_N a1 s1 T1.
Hypothesis order_wf: well_founded order.
(** Yet another alternative definition of [forever]. *)
CoInductive forever_plus : state -> traceinf -> Prop :=
| forever_plus_intro: forall s1 t s2 T1 T2,
plus s1 t s2 ->
forever_plus s2 T2 ->
T1 = t *** T2 ->
forever_plus s1 T1.
(** Infinitely many silent transitions *)
CoInductive forever_silent : state -> Prop :=
| forever_silent_intro: forall s1 s2,
step s1 E0 s2 -> forever_silent s2 ->
forever_silent s1.
(** An alternate definition. *)
CoInductive forever_silent_N : A -> state -> Prop :=
| forever_silent_N_star: forall s1 s2 a1 a2,
star s1 E0 s2 ->
order a2 a1 ->
forever_silent_N a2 s2 ->
forever_silent_N a1 s1
| forever_silent_N_plus: forall s1 s2 a1 a2,
plus s1 E0 s2 ->
forever_silent_N a2 s2 ->
forever_silent_N a1 s1.
(** Infinitely many non-silent transitions *)
CoInductive forever_reactive : state -> traceinf -> Prop :=
| forever_reactive_intro: forall s1 s2 t T,
star s1 t s2 -> t <> E0 -> forever_reactive s2 T ->
forever_reactive s1 (t *** T).

Lemma star_forever_reactive:
forall s1 t s2 T,
star s1 t s2 -> forever_reactive s2 T ->
forever_reactive s1 (t *** T).