Library branch_bisim

Require Import base.
Require Import prelim.
Require Import lts_tau.
Require Import bar_induction.

Module BRANCH_BISIM.
Import LTS_TAU.

Section branch_bisim. Context {Obs:ObservationSystem}.

  Definition branch : transition_diagram := fun X Y R x y =>
        (forall o x', steps X x o x' ->
          (o = None /\ R x' y) \/
          exists y', exists y'',
            path_where _ (steps_tau Y) (R x) y y' /\
            steps Y y' o y'' /\
            R x y' /\ R x' y'').

    Definition branch' : transition_diagram := fun X Y R x y =>
        (forall o x', steps X x o x' ->
          (o = None /\ R x' y) \/
          exists y', exists y'',
            steps_star Y y y' /\
            steps Y y' o y'' /\
            R x y' /\ R x' y'').

  Lemma branch_sim_eq : forall X, bisimulation branch X X eq.

  Lemma branch_sim_compose : forall X Y Z R1 R2,
    simulation branch X Y R1 ->
    simulation branch Y Z R2 ->
    simulation branch X Z (comp R1 R2).

  Lemma branch_bisim_compose : forall X Y Z R1 R2,
    bisimulation branch X Y R1 ->
    bisimulation branch Y Z R2 ->
    bisimulation branch X Z (comp R1 R2).

  Lemma bisimilar_refl : forall X x, bisimilar branch X X x x.

  Lemma bisimilar_trans : forall X Y Z x y z,
    bisimilar branch X Y x y ->
    bisimilar branch Y Z y z ->
    bisimilar branch X Z x z.

  Lemma bisimilar_branch_sim X Y : bisimulation branch X Y (bisimilar branch X Y).

  Definition stuttering_property X Y (R:state X -> state Y -> Prop) :=
    forall x y0 y y1,
      R x y0 -> R x y1 ->
      steps_star Y y0 y ->
      steps_star Y y y1 ->
      R x y.

  Definition stuttering_closure X Y (R:state X -> state Y -> Prop) x y :=
    exists x0, exists x1, exists y0, exists y1,
      steps_star X x0 x /\
      steps_star X x x1 /\
      steps_star Y y0 y /\
      steps_star Y y y1 /\
      R x0 y1 /\ R x1 y0.

  Lemma stuttering_closure_property : forall X Y R,
    stuttering_property X Y (stuttering_closure X Y R).

  Lemma stuttering_closure_property_inv : forall X Y R,
    stuttering_property Y X (inv (stuttering_closure X Y R)).

  Lemma inv_stuttering : forall X Y R,
    inv (stuttering_closure X Y R) =
    stuttering_closure Y X (inv R).

  Lemma stuttering_path : forall X Y (R:state X -> state Y -> Prop) y y1,
    steps_star Y y y1 ->
    forall x0 x1 y0,
      R x1 y0 -> R x0 y1 ->
      steps_star Y y0 y ->
      steps_star X x0 x1 ->
      path_where _ (steps_tau Y) (stuttering_closure X Y R x0) y y1.

  Lemma stuttering_closure_incl : forall X Y (R:state X -> state Y -> Prop) x y,
    R x y -> stuttering_closure X Y R x y.

  Lemma sim_stuttering_push : forall X Y R x y,
    simulation branch' X Y R ->
    stuttering_closure X Y R x y ->
    exists y',
      path_where _ (steps_tau Y) (fun y => stuttering_closure X Y R x y) y y' /\
      R x y'.

  Lemma stuttering_is_branch : forall X Y R,
    simulation branch' X Y R ->
    simulation branch' X Y (stuttering_closure X Y R).

  Lemma is_branch_branch' : forall X Y R,
    simulation branch X Y R ->
    simulation branch' X Y R.

  Lemma is_branch'_branch : forall X Y R,
    stuttering_property X Y R ->
    simulation branch' X Y R ->
    simulation branch X Y R.

  Lemma bisimilar_branch_branch' :
    bisimilar branch = bisimilar branch'.

  Lemma equiv_refl : forall x, equiv branch x x.

  Lemma equiv_sym : forall x y,
    equiv branch x y -> equiv branch y x.

  Lemma equiv_trans : forall x y z,
    equiv branch x y -> equiv branch y z -> equiv branch x z.


  Section divergence_sensitive_diagrams.
    Variables X Y:LTS.
    Variable R : state X -> state Y -> Prop.



    Inductive branch_ind : state X -> state Y -> Prop :=
      branch_ind_intro : forall x y,
        (forall o x', steps X x o x' ->
          (o = None /\ R x' y /\ branch_ind x' y) \/
          exists y', exists y'',
            path_where _ (steps_tau Y) (R x) y y' /\
            steps Y y' o y'' /\
            R x y' /\ R x' y'') ->
        branch_ind x y.

    Lemma branch_ind_ind :
      forall P : state X -> state Y -> Prop,
       (forall (x : state X) (y : state Y),
        (forall o x', steps X x o x' ->
          (o = None /\ R x' y /\ P x' y) \/
          exists y', exists y'',
            path_where _ (steps_tau Y) (R x) y y' /\
            steps Y y' o y'' /\
            R x y' /\ R x' y'') -> P x y) ->
       forall (s : state X) (s0 : state Y), branch_ind s s0 -> P s s0.

    Inductive branch_ind' : state X -> state Y -> Prop :=
      branch_ind'_intro : forall x y,
        (forall o x', steps X x o x' ->
          (o = None /\ R x' y /\ branch_ind' x' y) \/
          exists y', exists y'',
            steps_star Y y y' /\
            steps Y y' o y'' /\
            R x y' /\ R x' y'') ->
        branch_ind' x y.

    Lemma branch_ind'_ind :
      forall P : state X -> state Y -> Prop,
       (forall (x : state X) (y : state Y),
        (forall o x', steps X x o x' ->
          (o = None /\ R x' y /\ P x' y) \/
          exists y', exists y'',
            steps_star Y y y' /\
            steps Y y' o y'' /\
            R x y' /\ R x' y'') -> P x y) ->
       forall (s : state X) (s0 : state Y), branch_ind' s s0 -> P s s0.


    Definition cond_D R x y :=
        forall D,
          divergence_set X (fun x => R x y) D -> D x ->
          exists D',
            divergence_set Y (fun y => forall x, D x -> R x y) D' /\
            D' y.

    Definition cond_DX R x y :=
      diverges X (fun x => R x y) x ->
      diverges Y (fun y => R x y) y.

    Definition cond_D0 R x y :=
        forall D,
          divergence_set X (fun x => R x y) D -> D x ->
            exists x', exists y',
              path_where _ (steps_tau X) D x x' /\ D x' /\
              steps_tau Y y y' /\
              R x' y'.

    Definition cond_D1 R x y :=
        forall D,
          divergence_set X (fun x' => True) D -> D x ->
          exists x', exists y',
            D x' /\ steps_tau Y y y' /\
            R x' y'.

    Definition cond_D2 R x y :=
        forall D,
          divergence_set X (fun x' => True) D -> D x ->
          diverges Y (fun y' => exists x', D x' /\ R x' y') y.

    Lemma DX_interpolates : forall x y,
      (cond_D R x y -> cond_DX R x y) /\
      (cond_DX R x y -> cond_D0 R x y).

    Lemma D1_D2 :
      (forall x y, R x y -> cond_D1 R x y)
      <->
      (forall x y, R x y -> cond_D2 R x y).

  End divergence_sensitive_diagrams.

  Section ind_equiv.
    Variables X Y:LTS.
    Variable R : state X -> state Y -> Prop.

    Lemma branch_ind_branch : forall x y,
      branch_ind X Y R x y -> branch X Y R x y.

    Lemma branch_ind'_branch' : forall x y,
      branch_ind' X Y R x y -> branch' X Y R x y.

    Lemma branch_ind_ind' : forall x y,
      branch_ind X Y R x y ->
      branch_ind' X Y R x y.

    Lemma branch_ind'_ind_stuttering :
      simulation branch_ind' X Y R ->
      simulation branch_ind X Y (stuttering_closure X Y R).

  End ind_equiv.

  Theorem ind_equiv :
    bisimilar branch_ind = bisimilar branch_ind'.

  Section trans.
    Variables X Y Z:LTS.
    Variable R1 : state X -> state Y -> Prop.
    Variable R2 : state Y -> state Z -> Prop.

    Hypothesis HR1 : simulation branch_ind X Y R1.
    Hypothesis HR2 : simulation branch_ind Y Z R2.

    Lemma path_push_comp : forall (x : state X) (y1 y2 : state Y),
      path_where (state Y) (steps_tau Y) (R1 x) y1 y2 ->
      forall z1 : state Z,
        R2 y1 z1 ->
        exists z2 : state Z,
          path_where (state Z) (steps_tau Z) (comp R1 R2 x) z1 z2 /\ R2 y2 z2.

    Lemma branch_ind_compose_inner :
      forall x y z,
        R1 x y -> R2 y z ->

        (forall x x' y' y'',
          steps_tau X x x' ->
          path_where _ (steps_tau Y) (R1 x) y y' ->
          R1 x y ->
          R1 x y' ->
          steps_tau Y y' y'' ->
          R1 x' y'' ->

          comp R1 R2 x' z /\
          branch_ind X Z (comp R1 R2) x' z \/
          (exists z' : state Z,
            exists z'' : state Z,
              path_where _ (steps_tau Z) (comp R1 R2 x) z z' /\
              steps_tau Z z' z'' /\
              (comp R1 R2 x z') /\
              (comp R1 R2 x' z''))) ->

        branch_ind X Z (comp R1 R2) x z.

    Lemma branch_ind_compose :
      forall x z,
        comp R1 R2 x z ->
        branch_ind X Z (comp R1 R2) x z.
  End trans.

  Lemma bisimulation_ind_compose : forall X Y Z R1 R2,
    bisimulation branch_ind X Y R1 ->
    bisimulation branch_ind Y Z R2 ->
    bisimulation branch_ind X Z (comp R1 R2).

  Lemma branch_sim_ind_eq : forall X,
    simulation branch_ind X X eq.

  Lemma branch_ind_stutter : forall X Y R,
    bisimulation branch_ind X Y R ->
    bisimulation branch_ind X Y (stuttering_closure X Y R).

  Lemma branch_sim_ind_bisimilar : forall X Y,
    simulation branch_ind X Y (bisimilar branch_ind X Y).

  Theorem bisimilar_ind_refl : forall X x,
    bisimilar branch_ind X X x x.

  Theorem bisimilar_ind_trans : forall X Y Z x y z,
    bisimilar branch_ind X Y x y ->
    bisimilar branch_ind Y Z y z ->
    bisimilar branch_ind X Z x z.

  Theorem bisimulation_ind_bisimilar : forall X Y,
    bisimulation branch_ind X Y (bisimilar branch_ind X Y).

  Theorem bisimilar_ind_stuttering : forall X Y,
    bisimilar branch_ind X Y =
    stuttering_closure X Y (bisimilar branch_ind X Y).

Now show that branching bisimulation with property D1 is an equivalance relation closed under unions, and is stuttering closed.

  Lemma branch_sim_D1_compose : forall X Y Z R1 R2,
    simulation (td_and branch cond_D1) X Y R1 ->
    simulation (td_and branch cond_D1) Y Z R2 ->
    simulation (td_and branch cond_D1) X Z (comp R1 R2).

  Lemma bisimilar_D1_eq : forall X , bisimulation (td_and branch cond_D1) X X eq.

  Theorem bisimilar_D1_refl : forall X x,
    bisimilar (td_and branch cond_D1) X X x x.

  Theorem bisimilar_D1_trans : forall X Y Z x y z,
    bisimilar (td_and branch cond_D1) X Y x y ->
    bisimilar (td_and branch cond_D1) Y Z y z ->
    bisimilar (td_and branch cond_D1) X Z x z.

  Lemma simulation_bisimilar_D1 : forall X Y,
    simulation (td_and branch cond_D1) X Y
     (bisimilar (td_and branch cond_D1) X Y).

  Theorem bisimulation_bisimilar_D1 : forall X Y,
    bisimulation (td_and branch cond_D1) X Y
     (bisimilar (td_and branch cond_D1) X Y).

  Lemma simulation_D1_stuttering : forall X Y R,
    simulation (td_and branch cond_D1) X Y R ->
    simulation (td_and branch cond_D1) X Y (stuttering_closure X Y R).

  Lemma bisimulation_D1_stuttering : forall X Y R,
    bisimulation (td_and branch cond_D1) X Y R ->
    bisimulation (td_and branch cond_D1) X Y (stuttering_closure X Y R).

  Theorem bisimilar_D1_stuttering_closed : forall X Y,
    bisimilar (td_and branch cond_D1) X Y =
    stuttering_closure X Y (bisimilar (td_and branch cond_D1) X Y).

  Lemma stuttering_closure_idem : forall X Y R x y,
    stuttering_closure X Y (stuttering_closure X Y R) x y ->
    stuttering_closure X Y R x y.


  Lemma branch_ind_D1 : forall X Y R,
    simulation branch_ind X Y R ->
    simulation (td_and branch cond_D1) X Y R.

  Lemma branch_ind_D1_bisim : forall X Y R,
    bisimulation branch_ind X Y R ->
    bisimulation (td_and branch cond_D1) X Y R.

  Lemma D1_branch_ind_classic {Classic:EM} : forall X Y R,
    simulation (td_and branch cond_D1) X Y R ->
    simulation branch_ind X Y R.

  Lemma bisim_D1_branch_ind {Classic:EM} X Y R :
    bisimulation branch_ind X Y R <-> bisimulation (td_and branch cond_D1) X Y R.

  Fixpoint path_st (X:LTS) (x0:state X) (p:list (state X)) (xz:state X) :=
    match p with
    | nil => x0 = xz
    | (a::p') => path_st X x0 p' a /\ steps_tau X a xz
    end.

  Definition is_taupath_aux L x1 l xz :=
  match l with
  | nil => steps_tau L xz x1
  | x2::_ => steps_tau L x2 x1
  end.

  Fixpoint is_taupath (L:LTS) (xz:state L) (l:list (state L)) {struct l} :=
  match l with
  | nil => True
  | x1::l' => is_taupath_aux L x1 l' xz /\ is_taupath L xz l'
  end.

  Program Definition taupath_rule L xz (P:state L -> Prop): rule (state L) :=
    Build_rule (state L) (fun l => is_taupath L xz l /\ (forall x, In x l -> P x)) _ _.

  Fixpoint path_run (X:LTS) (x0:state X) (p:list (state X)) (xz:state X) :=
    match p with
    | nil => xz = x0
    | (a::p') => exists r', path_run X x0 p' r' /\ steps_tau X r' xz /\ xz = a
    end.

  Lemma path_run_ex_uniq : forall X x0 p, is_taupath X x0 p -> exists! r, path_run X x0 p r.

  Lemma sim_branch_stutter X Y R :
    simulation branch X Y R ->
    simulation branch X Y (stuttering_closure X Y R).

  Section D0_branch_ind.
    Variable Bw : brouwer_thesis_on_games.
    Variables X Y:LTS.
    Variable R : state X -> state Y -> Prop.
    Variable H : simulation branch X Y R.
    Variable x : state X.
    Variable y : state Y.
    Variable Hxy : R x y.

    Definition D0bar p :=
      exists hx, path_run X x p hx /\
        exists y', steps_tau Y y y' /\ stuttering_closure X Y R hx y'.

    Definition D0bar_Q p :=
      exists hx, path_run X x p hx /\ branch_ind' X Y (stuttering_closure X Y R) hx y.

    Lemma D0bar_in_D0bar_Q : forall p,
      taupath_rule X x (fun z => R z y) p ->
      D0bar p -> D0bar_Q p.

    Lemma D0bar_mono : forall p a,
      taupath_rule X x (fun z => R z y) (a::p) ->
      D0bar p -> D0bar (a::p).

    Lemma D0bar_Q_hered : forall p,
      (taupath_rule X x (fun z => R z y)) p ->
      (forall a : state X,
        (taupath_rule X x (fun z => R z y)) (a :: p) ->
        D0bar_Q (a :: p)) -> D0bar_Q p.

  Lemma D0_branch_ind :
    simulation cond_D0 X Y R ->
    branch_ind' X Y (stuttering_closure X Y R) x y.

  End D0_branch_ind.

  Lemma bisimilar_change_cond_sim : forall
    (D1 D2:forall X Y, (state X -> state Y -> Prop) -> state X -> state Y -> Prop),
    (forall X Y x y,
      bisimilar (td_and branch D1) X Y x y ->
      D2 X Y (bisimilar (td_and branch D1) X Y) x y) ->
    (forall X Y,
      simulation (td_and branch D2) X Y
        (bisimilar (td_and branch D1) X Y)).

  Lemma bisimilar_change_cond_bisim : forall
    (D1 D2:forall X Y, (state X -> state Y -> Prop) -> state X -> state Y -> Prop),
    (forall X Y x y,
      bisimilar (td_and branch D1) X Y x y ->
      D2 X Y (bisimilar (td_and branch D1) X Y) x y) ->
    (forall X Y,
      bisimulation (td_and branch D2) X Y (bisimilar (td_and branch D1) X Y)).

  Lemma bisimilar_change_cond : forall
    (D1 D2:forall X Y, (state X -> state Y -> Prop) -> state X -> state Y -> Prop),
    (forall X Y x y,
      bisimilar (td_and branch D1) X Y x y ->
      D2 X Y (bisimilar (td_and branch D1) X Y) x y) ->
    (forall X Y x y,
      bisimilar (td_and branch D1) X Y x y ->
      bisimilar (td_and branch D2) X Y x y).

  Lemma bisimilar_D1_cond_D0 : forall X Y x y,
    bisimilar (td_and branch cond_D1) X Y x y ->
    cond_D0 X Y (bisimilar (td_and branch cond_D1) X Y) x y.

  Lemma bisimilar_D1_D0 : forall X Y x y,
    bisimilar (td_and branch cond_D1) X Y x y ->
    bisimilar (td_and branch cond_D0) X Y x y.

  Lemma sim_D0_stuttering_ind {Bw:brouwer_thesis_on_games} : forall X Y R,
    simulation (td_and branch cond_D0) X Y R ->
    simulation branch_ind' X Y (stuttering_closure X Y R).

  Lemma D1_D0_sim : forall X Y R,
    simulation cond_D1 X Y R ->
    simulation cond_D0 X Y R.

  Theorem D1_branch_ind_bisimilar {Bw:brouwer_thesis_on_games} :
    forall X Y x y,
      bisimilar branch_ind X Y x y <-> bisimilar (td_and branch cond_D1) X Y x y.

  Lemma bisimilar_D1_cond_D : forall X Y x y,
    bisimilar (td_and branch cond_D1) X Y x y ->
    cond_D X Y (bisimilar (td_and branch cond_D1) X Y) x y.

  Lemma bisimilar_D1_D : forall X Y x y,
    bisimilar (td_and branch cond_D1) X Y x y ->
    bisimilar (td_and branch cond_D) X Y x y.

  Lemma cond_D_D0 : forall X Y R x y,
    cond_D X Y R x y ->
    cond_D0 X Y R x y.

  Lemma bisimilar_D_D0 : forall X Y x y,
    bisimilar (td_and branch cond_D) X Y x y ->
    bisimilar (td_and branch cond_D0) X Y x y.

  Lemma sim_D0_stuttering_D1 {Bw:brouwer_thesis_on_games} : forall X Y R,
    simulation (td_and branch cond_D0) X Y R ->
    simulation (td_and branch cond_D1) X Y
      (stuttering_closure X Y (stuttering_closure X Y R)).

  Lemma bisimilar_D0_D1 {Bw:brouwer_thesis_on_games} : forall X Y x y,
    bisimilar (td_and branch cond_D0) X Y x y ->
    bisimilar (td_and branch cond_D1) X Y x y.

  Theorem interpolates_D_D0_equal {Bw:brouwer_thesis_on_games} :
    forall (T:transition_diagram),
    (forall X Y R x y, cond_D X Y R x y -> T X Y R x y) ->
    (forall X Y R x y, T X Y R x y -> cond_D0 X Y R x y) ->
    bisimilar (td_and branch T) = bisimilar (td_and branch cond_D).

  Theorem bisimilar_equal_D_D0 {Bw:brouwer_thesis_on_games} : forall X Y,
    bisimilar (td_and branch cond_D) X Y =
    bisimilar (td_and branch cond_D0) X Y.

  Theorem bisimilar_equal_D_D1 {Bw:brouwer_thesis_on_games} : forall X Y,
    bisimilar (td_and branch cond_D) X Y =
    bisimilar (td_and branch cond_D1) X Y.

  Theorem bisimilar_equal_D_DX {Bw:brouwer_thesis_on_games} : forall X Y,
    bisimilar (td_and branch cond_D) X Y =
    bisimilar (td_and branch cond_DX) X Y.

  Theorem bisimilar_bisimulation_D {Bw:brouwer_thesis_on_games} X Y :
    bisimulation (td_and branch cond_D) X Y
      (bisimilar (td_and branch cond_D) X Y).

  Lemma loop_simulation X : simulation branch_ind X X (fun x y => steps_star X x y /\ steps_star X y x).

  Lemma loop_bisimulation X : bisimulation branch_ind X X (fun x y => steps_star X x y /\ steps_star X y x).

  Definition droploop X := Build_LTS (state X)
    (fun x o x' => steps X x o x' /\
      (o = None -> x = x' -> False)).

  Definition weak_converges X x :=
    converges (droploop X) (fun _ => False) x.

  Lemma finite_divergences_step_star {Classic:EM} X :
    forall x1 x2,
      steps_star X x1 x2 ->
      finite_divergences X x1 ->
      finite_divergences X x2.

End branch_bisim.

  Module quotient.
  Section quotient.
    Context {Classic:EM}.
    Context {Obs:ObservationSystem}.
    Variables X:LTS.

    Definition is_quot (S: state X -> Prop) :=
      (exists x, S x) /\
      (forall x1 x2, S x1 -> (bisimilar (td_and branch cond_D1) X X x1 x2 <-> S x2)).

    Definition quot := { S : state X -> Prop | is_quot S }.
    Definition in_quot (q:quot): state X -> Prop := proj1_sig q.
    Inductive quot_step : forall (q:quot) (o:option O) (q':quot), Prop :=
      | qst_main : forall q o q' x x',
          (o = None -> bisimilar (td_and branch cond_D1) X X x x' -> False) ->
          in_quot q x ->
          in_quot q' x' ->
          steps X x o x' ->
          quot_step q o q'

      | qst_loop : forall q x,
          in_quot q x ->
          diverges X (fun z => bisimilar (td_and branch cond_D1) X X z x) x ->
          quot_step q None q.

    Definition quotLTS : LTS := Build_LTS quot quot_step.

    Program Definition mkq (x:state X) : quot :=
      fun x' => bisimilar (td_and branch cond_D1) X X x x'.

    Lemma quot_bisim : bisimulation (td_and branch cond_D1) quotLTS X in_quot.

    Theorem quot_weak_converges : forall x q,
      in_quot q x ->
      finite_divergences X x ->
      weak_converges quotLTS q.
  End quotient.
  End quotient.

Section D0_to_brouwer.
  Hypothesis D0_sim_implies_ind_sim : forall (Obs:ObservationSystem) (X Y:LTS) x y,
    (exists R, simulation (td_and branch cond_D0) X Y R /\ R x y) ->
    (exists R, simulation branch_ind X Y R /\ R x y).

    Variable A:Type.
    Variable rule:rule A.

    Variable B:list A -> Prop.
    Hypothesis Bbar : bar rule B.

    Inductive rule_state :=
    | rs_seq : forall l:list A, rule l -> rule_state
    | rs_init : rule_state.

    Inductive rule_transition : rule_state -> option (list A) -> rule_state -> Prop :=
    | rule_identify : forall l H,
           rule_transition (rs_seq l H) (Some l) (rs_seq l H)
    | rule_init_identify : forall l,
           rule_transition rs_init (Some l) rs_init
    | rule_step : forall l a Hl Hal,
           rule_transition (rs_seq l Hl) None (rs_seq (a::l) Hal)
    | rule_init_step : forall l1 l2 H,
           B l1 ->
           rule_transition rs_init None (rs_seq (l2++l1) H).

    Instance rule_obs_system : ObservationSystem :=
      { O := list A; observations_inhabited := nil }.
    Definition ruleLTS := Build_LTS rule_state rule_transition.

    Inductive rule_state_match : rule_state -> rule_state -> Prop :=
    | rsm_seq : forall l H1 H2, rule_state_match (rs_seq l H1) (rs_seq l H2)
    | rsm_init : forall l H, rule_state_match (rs_seq l H) rs_init.

    Lemma rule_state_branch_sim : simulation branch ruleLTS ruleLTS rule_state_match.

    Lemma rule_state_D0_sim : simulation cond_D0 ruleLTS ruleLTS rule_state_match.

    Lemma sim_seq_prefix : forall R l1 H1 l2 H2,
      simulation branch_ind ruleLTS ruleLTS R ->
      R (rs_seq l1 H1) (rs_seq l2 H2) ->
      exists l3, l1 = l3++l2.

    Lemma branch_ind_securable : forall R l H,
      simulation branch_ind ruleLTS ruleLTS R ->
      R (rs_seq l H) rs_init ->
      securable rule B l.

    Lemma D0_to_brouwer : securable rule B nil.
  End D0_to_brouwer.

  Theorem D0_ind_equiv_iff_brouwer_on_games :
    (forall (Obs:ObservationSystem) (X Y:LTS) x y,
      (exists R, simulation (td_and branch cond_D0) X Y R /\ R x y) ->
      (exists R, simulation branch_ind X Y R /\ R x y))
    <->
    brouwer_thesis_on_games.

  Theorem D0_ind_equiv_LPO :
    (forall (Obs:ObservationSystem) (X Y:LTS) x y,
      (exists R, simulation (td_and branch cond_D0) X Y R /\ R x y) ->
      (exists R, simulation branch_ind X Y R /\ R x y)) ->

    limited_principle_of_omniscience.
End BRANCH_BISIM.