semantics.tower.ex_streams

Require Import base ord data.fintype.
Require Import tower.tarski tower.tower tower.direct_induction tower.cocontinuous_tower.

Section Streams.
Variable A : Type.

Stream equality as a coinductive definition


Definition SA := nat -> A.

Definition ε (R : Rel SA) : Rel SA :=
  fun f g => f 0 = g 0 /\ R (S >> f) (S >> g).

Global Instance ε_mono :
  monotone ε.
Proof.
  move=> R S le_R_S f g [h t]. split=> //. exact: le_R_S.
Qed.

Definition bisim : Rel SA := gfp ε.

Lemma bisim_def :
  bisim = (fun f g => exists2 R : Rel SA, R f g & (R ε R)).
Proof.
  fext=> f g. rewrite/bisim gfp_def. rewrite !prod_exE prop_exE /supguard/=.
  apply: pext. case=> R H. rewrite !prod_exE prop_exE in H. case: H; by exists R.
  case=> R rfg rbsim. exists R. rewrite !prod_exE prop_exE. by exists rbsim.
Qed.

Lemma bisim_eq :
  bisim = eq.
Proof.
  rewrite bisim_def. apply: le_eq; hnf=>/=f; hnf=>/=g; hnf=>H.
  - case: H => R rfg rbsim. fext=>n. elim: n f g rfg.
    + move=> f g rfg. by case: (rbsim f g rfg).
    + move=> n ih f g rfg. case: (rbsim f g rfg) => _ H. exact: ih H.
  - exists eq => // f' g' ->. by split.
Qed.

Companion for stream equality


Local Notation rbisim R := (t ε R).

Lemma rbisim_refl R f : rbisim R f f.
Proof.
  apply: (@t_monotone _ ε ) => //. by rewrite t_gfp -/bisim bisim_eq.
Qed.

Lemma rbisim_equivalence R :
  Equivalence (rbisim R).
Proof.
  move: R. apply tower_induction.
  - move=> I F ih. constructor. move=> x i. reflexivity.
    move=> x y rxy i. symmetry. exact: rxy.
    move=> x y z rxy ryz i. transitivity y. exact: rxy. exact: ryz.
  - move=> /= R equ. constructor.
    + move=> x. split=> //. reflexivity.
    + move=> x y [rxy0 rxyS]. split; by symmetry.
    + move=> x y z [rxy0 rxyS] [ryz0 ryzS]. split; etransitivity; by eauto.
Qed.

Inductive ctx_operator (c : SA -> SA) (R : Rel SA) : Rel SA :=
| CtxOperator f g : R f g -> ctx_operator c R (c f) (c g).

Lemma upto_context (c : SA -> SA) :
  (forall R,
      (forall f g, rbisim R f g -> rbisim R (c f) (c g)) ->
      (forall f g, ε (rbisim R) f g -> ε (rbisim R) (c f) (c g))) ->
  (forall R f g, rbisim R f g -> rbisim R (c f) (c g)).
Proof.
  move=> h1. suff/=: forall R, ctx_operator c (rbisim R) rbisim R.
  move=> /=h2 R f g h3. apply: h2. by constructor. apply: upto_lemma.
  - move=> /= R S le_R_S. hnf=> f. hnf=> g. hnf=> h.
    inversion_clear h. constructor. exact: le_R_S.
  - move=> /= R h2. move=> f. move=> g. move=> h. inversion_clear h.
    apply: h1 => // f' g' h'. apply: h2. by constructor.
Qed.

Cocontinuity


Definition neq n (f g : SA) :=
  forall m, m < n -> f m = g m.
Definition stream_companion (R : Rel SA) (f g : SA) : Prop :=
  forall n, (R neq n) -> neq n f g.

Lemma ε_cocontinuous I (F : I -> Rel SA) :
  I -> codirected F -> i, ε (F i) ε (inf F).
Proof.
  move=> i0 co. hnf=> f. hnf=> g. rewrite !prod_allE prop_leE prop_allE => H.
  rewrite/ε. split; first by case: (H i0).
  rewrite !prod_allE prop_allE => i. by case: (H i).
Qed.

Lemma stream_companionP R :
  stream_companion R = rbisim R.
Proof.
  rewrite -kleene_t_is_t; last by exact: ε_cocontinuous.
  suff: chain ε = neq by rewrite/kleene_t => ->.
  fext=> n f g. elim: n f g => /=[|n ih] f g.
  - rewrite !prod_topE prop_topE /neq. exact: pext.
  - apply: le_eq.
    + move=> H m lt. case: H => e1. rewrite ih => /(_ _) e2. destruct m => //.
      apply: e2. exact: lt.
    + move=> H. split. exact: H. rewrite ih => m lt. apply: H. exact: lt.
Qed.

End Streams.