(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.(** The general form of a backward simulation. *)

Record bsim_properties (L1 L2: semantics) (index: Type)
                       (order: index -> index -> Prop)
                       (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    bsim_order_wf: well_founded order;
    bsim_start_stacks_exist:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg ->
                     exists s2, start_stack L2 m0 s2 f arg;
    bsim_initial_states_exist:
      forall s1, initial_state L1 s1 ->
                     exists s2, initial_state L2 s2;
    bsim_match_start_stacks:
      forall s1 s2 f arg m0, start_stack L1 m0 s1 f arg  ->
                  start_stack L2 m0 s2 f arg  ->
                  exists i, exists s1', start_stack L1 m0 s1' f arg /\ match_states i s1' s2;
    bsim_match_initial_states:
      forall s1 s2, initial_state L1 s1  ->
                  initial_state L2 s2  ->
                  exists i, exists s1', initial_state L1 s1' /\ match_states i s1' s2;
    bsim_match_final_states:
      forall i s1 s2 r,
      match_states i s1 s2 -> safe L1 s1 -> final_state L2 s2 r ->
      exists s1', Star L1 s1 E0 s1' /\ final_state L1 s1' r;
    bsim_progress:
      forall i s1 s2,
      match_states i s1 s2 -> safe L1 s1 ->
      (exists r, final_state L2 s2 r) \/
      (exists t, exists s2', Step L2 s2 t s2');
    bsim_simulation:
      forall s2 t s2', Step L2 s2 t s2' ->
      forall i s1, match_states i s1 s2 -> safe L1 s1 ->
      exists i', exists s1',
         (Plus L1 s1 t s1' \/ (Star L1 s1 t s1' /\ order i' i))
      /\ match_states i' s1' s2';
    bsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
  }.Inductive backward_simulation (L1 L2: semantics) : Prop :=
  Backward_simulation (index: Type)
                      (order: index -> index -> Prop)
                      (match_states: index -> state L1 -> state L2 -> Prop)
                      (props: bsim_properties L1 L2 index order match_states).Inductive backward_simulation (L1 L2: semantics) : Prop :=
  Backward_simulation (index: Type)
                      (order: index -> index -> Prop)
                      (match_states: index -> state L1 -> state L2 -> Prop)
                      (props: bsim_properties L1 L2 index order match_states).

(* Specifications: *)
Lemma bsim_simulation': forall L1 L2 index order match_states, bsim_properties L1 L2 index order match_states -> forall i s2 t s2', Step L2 s2 t s2' -> forall s1, match_states i s1 s2 -> safe L1 s1 -> (exists i', exists s1', Plus L1 s1 t s1' /\ match_states i' s1' s2') \/ (exists i', order i' i /\ t = E0 /\ match_states i' s1 s2').
Lemma backward_simulation_plus: backward_simulation L1 L2.
Lemma bsim_E0_star: forall s2 s2', Star L2 s2 E0 s2' -> forall i s1, match_states i s1 s2 -> safe L1 s1 -> exists i', exists s1', Star L1 s1 E0 s1' /\ match_states i' s1' s2'.
Lemma bsim_safe: forall i s1 s2, match_states i s1 s2 -> safe L1 s1 -> safe L2 s2.
Lemma bsim_E0_plus: forall s2 t s2', Plus L2 s2 t s2' -> t = E0 -> forall i s1, match_states i s1 s2 -> safe L1 s1 -> (exists i', exists s1', Plus L1 s1 E0 s1' /\ match_states i' s1' s2') \/ (exists i', clos_trans _ order i' i /\ match_states i' s1 s2').
Lemma star_non_E0_split: forall s2 t s2', Star L2 s2 t s2' -> (length t = 1)%nat -> exists s2x, exists s2y, Star L2 s2 E0 s2x /\ Step L2 s2x t s2y /\ Star L2 s2y E0 s2'.