Definition op_eq_dec : forall x y : op key, {x = y} + {x <> y}.Inductive exported (env_i : key -> option input) (env_o : key -> option output) :
    list (IR key) -> list (input * output) -> Prop :=
  | exported_nil : exported env_i env_o nil nil
  | exported_IO : forall k i o l tr,
                    env_i k = Some i ->
                    env_o k = Some o ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRO k :: l) ((i, o) :: tr)
  | exported_IU : forall k i o l tr,
                    env_i k = Some i ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRU k :: l) ((i, o) :: tr).Inductive exported (env_i : key -> option input) (env_o : key -> option output) :
    list (IR key) -> list (input * output) -> Prop :=
  | exported_nil : exported env_i env_o nil nil
  | exported_IO : forall k i o l tr,
                    env_i k = Some i ->
                    env_o k = Some o ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRO k :: l) ((i, o) :: tr)
  | exported_IU : forall k i o l tr,
                    env_i k = Some i ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRU k :: l) ((i, o) :: tr).Inductive exported (env_i : key -> option input) (env_o : key -> option output) :
    list (IR key) -> list (input * output) -> Prop :=
  | exported_nil : exported env_i env_o nil nil
  | exported_IO : forall k i o l tr,
                    env_i k = Some i ->
                    env_o k = Some o ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRO k :: l) ((i, o) :: tr)
  | exported_IU : forall k i o l tr,
                    env_i k = Some i ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRU k :: l) ((i, o) :: tr).Inductive exported (env_i : key -> option input) (env_o : key -> option output) :
    list (IR key) -> list (input * output) -> Prop :=
  | exported_nil : exported env_i env_o nil nil
  | exported_IO : forall k i o l tr,
                    env_i k = Some i ->
                    env_o k = Some o ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRO k :: l) ((i, o) :: tr)
  | exported_IU : forall k i o l tr,
                    env_i k = Some i ->
                    exported env_i env_o l tr ->
                    exported env_i env_o (IRI k :: IRU k :: l) ((i, o) :: tr).

(* Specifications: *)
Lemma has_key_intro : forall e, has_key (eClient e) (eId e) e = true.
Lemma has_key_intro' : forall e c i, eClient e = c -> eId e = i -> has_key c i e = true.
Lemma has_key_different_id_false : forall e e', eId e <> eId e' -> has_key (eClient e) (eId e) e' = false.
Lemma has_key_different_client_false : forall e e', eClient e <> eClient e' -> has_key (eClient e) (eId e) e' = false.
Lemma deduplicate_log'_In : forall l e, In e l -> forall ks, (forall i, assoc clientId_eq_dec ks (eClient e) = Some i -> i < eId e) -> (forall id', before_func (has_key (eClient e) id') (has_key (eClient e) (eId e)) l -> id' <= eId e) -> (exists e', eClient e' = eClient e /\ eId e' = eId e /\ In e' (deduplicate_log' l ks)).
Lemma deduplicate_log_In : forall l e, In e l -> (forall id', before_func (has_key (eClient e) id') (has_key (eClient e) (eId e)) l -> id' <= eId e) -> exists e', eClient e' = eClient e /\ eId e' = eId e /\ In e' (deduplicate_log l).
Lemma deduplicate_log_In_if : forall l e, In e (deduplicate_log l) -> In e l.
Lemma log_to_IR_good_trace : forall env_o log, good_trace _ (log_to_IR env_o log).
Lemma in_import_in_trace_O : forall tr k, In (O k) (import tr) -> exists os h, In (h, inr os) tr /\ exists o, In (ClientResponse (fst k) (snd k) o) os.
Lemma in_import_in_trace_I : forall tr k, In (I k) (import tr) -> exists h i, In (h, inl (ClientRequest (fst k) (snd k) i)) tr.
Lemma in_applied_entries_in_IR : forall log e client id env, eClient e = client -> eId e = id -> In e log -> (exists o, env (client, id) = Some o) -> In (IRO (client, id)) (log_to_IR env log).
Theorem In_get_output' : forall l client id o, In (ClientResponse client id o) l -> exists o', get_output' l (client, id) = Some o'.
Theorem import_get_output : forall tr k, In (O k) (import tr) -> exists o, get_output tr k = Some o.
Lemma IRO_in_IR_in_log : forall k log tr, In (IRO k) (log_to_IR (get_output tr) log) -> exists e out, eClient e = fst k /\ eId e = snd k /\ get_output tr k = Some out /\ In e log.
Lemma get_output'_In : forall l k out, get_output' l k = Some out -> In (ClientResponse (fst k) (snd k) out) l.
Lemma get_output_import_O : forall tr k out, get_output tr k = Some out -> In (O k) (import tr).
Lemma IRU_in_IR_in_log : forall k log tr, In (IRU k) (log_to_IR (get_output tr) log) -> exists e, eClient e = fst k /\ eId e = snd k /\ get_output tr k = None /\ In e log.
Lemma trace_I_in_import : forall tr k h i, In (h, inl (ClientRequest (fst k) (snd k) i)) tr -> In (I k) (import tr).
Lemma get_IR_input_of_log_to_IR : forall env log, get_IR_input_keys _ (log_to_IR env log) = map (fun e => (eClient e, eId e)) log.
Lemma get_IR_output_of_log_to_IR : forall env log, get_IR_output_keys _ (log_to_IR env log) = map (fun e => (eClient e, eId e)) log.
Lemma NoDup_input_import : forall tr, NoDup (get_op_input_keys key (import tr)).
Lemma NoDup_output_import : forall tr, NoDup (get_op_output_keys key (import tr)).
Lemma before_import_output_before_input : forall k k' tr, before (O k) (I k') (import tr) -> output_before_input (fst k) (snd k) (fst k') (snd k') tr.
Lemma has_key_true_key_of : forall c i e, has_key c i e = true -> key_of e = (c, i).
Lemma key_of_has_key_true : forall c i e, key_of e = (c, i) -> has_key c i e = true.
Lemma has_key_false_key_of : forall c i e, has_key c i e = false -> key_of e <> (c, i).
Lemma key_of_has_key_false : forall c i e, key_of e <> (c, i) -> has_key c i e = false.
Lemma has_key_true_same_client : forall c i e, has_key c i e = true -> eClient e = c.
Lemma has_key_true_same_id : forall c i e, has_key c i e = true -> eId e = i.
Lemma has_key_true_elim : forall c i e, has_key c i e = true -> eClient e = c /\ eId e = i.
Lemma has_key_false_elim : forall c i e, has_key c i e = false -> eClient e <> c \/ eId e <> i.
Lemma before_func_deduplicate' : forall l k k' ks, before_func (has_key (fst k) (snd k)) (has_key (fst k') (snd k')) l -> (forall id', before_func (has_key (fst k) id') (has_key (fst k) (snd k)) l -> id' <= snd k) -> (forall i, assoc clientId_eq_dec ks (fst k) = Some i -> i < snd k) -> before_func (has_key (fst k) (snd k)) (has_key (fst k') (snd k')) (deduplicate_log' l ks).
Lemma before_func_deduplicate : forall k k' l, before_func (has_key (fst k) (snd k)) (has_key (fst k') (snd k')) l -> (forall id', before_func (has_key (fst k) id') (has_key (fst k) (snd k)) l -> id' <= snd k) -> before_func (has_key (fst k) (snd k)) (has_key (fst k') (snd k')) (deduplicate_log l).
Lemma entries_ordered_before_log_to_IR : forall k k' net failed tr, step_failure_star step_failure_init (failed, net) tr -> In (O k) (import tr) -> k <> k' -> entries_ordered (fst k) (snd k) (fst k') (snd k') net -> before (IRO k) (IRI k') (log_to_IR (get_output tr) (deduplicate_log (applied_entries (nwState net)))).
Lemma input_before_output_import : forall tr k, before_func (is_input_with_key (fst k) (snd k)) (is_output_with_key (fst k) (snd k)) tr -> before (I k) (O k) (import tr).
Lemma I_before_O : forall failed net tr k, step_failure_star step_failure_init (failed, net) tr -> In (O k) (import tr) -> before (I k) (O k) (import tr).
Lemma get_IR_input_keys_log_to_IR : forall l env_o, get_IR_input_keys key (log_to_IR env_o l) = map (fun e => (eClient e, eId e)) l.
Lemma get_IR_output_keys_log_to_IR : forall l env_o, get_IR_output_keys key (log_to_IR env_o l) = map (fun e => (eClient e, eId e)) l.
Lemma deduplicate_log'_ks : forall l ks e id, In e (deduplicate_log' l ks) -> assoc clientId_eq_dec ks (eClient e) = Some id -> id < (eId e).
Lemma NoDup_deduplicate_log' : forall l ks, NoDup (map (fun e => (eClient e, eId e)) (deduplicate_log' l ks)).
Lemma NoDup_deduplicate_log : forall l, NoDup (map (fun e => (eClient e, eId e)) (deduplicate_log l)).
Lemma NoDup_input_log : forall l env_o, NoDup (get_IR_input_keys key (log_to_IR env_o (deduplicate_log l))).
Lemma NoDup_output_log : forall l env_o, NoDup (get_IR_output_keys key (log_to_IR env_o (deduplicate_log l))).
Lemma log_to_IR_app : forall xs ys env, log_to_IR env (xs ++ ys) = log_to_IR env xs ++ log_to_IR env ys.
Lemma exported_execute_log' : forall env_i env_o l es tr st, (forall e, In e l -> env_i (eClient e, eId e) = Some (eInput e)) -> (forall xs ys e tr' st' o o0 st'', l = xs ++ e :: ys -> execute_log' xs st tr = (tr', st') -> handler (eInput e) st' = (o, st'') -> env_o (eClient e, eId e) = Some o0 -> o = o0) -> execute_log es = (tr, st) -> exported env_i env_o (log_to_IR env_o es) tr -> exported env_i env_o (log_to_IR env_o (es ++ l)) (fst (execute_log' l st tr)).
Lemma exported_execute_log : forall env_i env_o l, (forall e, In e l -> env_i (eClient e, eId e) = Some (eInput e)) -> (forall xs ys e tr' st' o o0 st'', l = xs ++ e :: ys -> execute_log xs = (tr', st') -> handler (eInput e) st' = (o, st'') -> env_o (eClient e, eId e) = Some o0 -> o = o0) -> exported env_i env_o (log_to_IR env_o l) (fst (execute_log l)).