(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.(** The general form of a forward simulation. *)
(** NEW: I will tolerate the duplication of start_stacks/initial_states, while 
    we find a better abstraction. *)
Record fsim_properties (index: Type)
          (order: index -> index -> Prop)
          (match_states: index -> state L1 -> state L2 -> Prop) : Prop := {
    fsim_order_wf: well_founded order;
    fsim_match_start_stacks:
      forall s1 f arg m0, start_stack L1 m0 s1 f arg  ->
                  exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2;
    fsim_match_initial_states:
      forall s1, initial_state L1 s1  -> 
            exists i, exists s2, initial_state L2 s2 /\ match_states i s1 s2;
    fsim_match_final_states:
      forall i s1 s2 r,
        match_states i s1 s2 -> final_state L1 s1 r -> final_state L2 s2 r;
    fsim_simulation:
      forall s1 t s1', Step L1 s1 t s1' ->
                  forall i s2, match_states i s1 s2 ->
                          exists i', exists s2', 
                              (Plus L2 s2 t s2' \/ (Star L2 s2 t s2' /\ order i' i))
                              /\ match_states i' s1' s2';
    fsim_public_preserved:
      forall id, Senv.public_symbol (symbolenv L2) id = Senv.public_symbol (symbolenv L1) id
                                                                }.

(* Specifications: *)
Lemma init_states_from_entry_index: forall (INIT_MEM: forall m, init_mem L1 = Some m -> init_mem L2 = Some m) (INIT_BLOCK: main_block L1 = main_block L2), forall index match_states (fsim_match_start_stacks: forall (s1:state L1) f arg m0, start_stack L1 m0 s1 f arg -> exists i, exists s2, start_stack L2 m0 s2 f arg /\ match_states i s1 s2), forall s1, initial_state L1 s1 -> exists (i:index), exists s2, initial_state L2 s2 /\ match_states i s1 s2.
Lemma init_states_from_entry: forall (INIT_MEM: forall m, init_mem L1 = Some m -> init_mem L2 = Some m) (INIT_BLOCK: main_block L1 = main_block L2), forall match_states (fsim_match_start_stacks: forall (s1:state L1) f arg m0, start_stack L1 m0 s1 f arg -> exists s2, start_stack L2 m0 s2 f arg /\ match_states s1 s2), forall s1, initial_state L1 s1 -> exists s2, initial_state L2 s2 /\ match_states s1 s2.