Section ForwardSimulations.
Context (L1 L2: semantics).
(** 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
}.

(*In the case where initial_memories are equal, initial_states follows from start_stacks. *)
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.