Theory Fused_Resource
theory Fused_Resource imports
  Fold_Spmf
begin
context includes ℐ.lifting begin
lift_definition eℐ :: "('a, 'b) ℐ ⇒ ('a, 'b × 'c) ℐ" is "λℐ x. ℐ x × UNIV" .
lemma outs_ℐ_eℐ[simp]: "outs_ℐ (eℐ ℐ) = outs_ℐ ℐ"
  by transfer simp
lemma responses_ℐ_eℐ [simp]: "responses_ℐ (eℐ ℐ) x = responses_ℐ ℐ x × UNIV"
  by transfer simp
lemma eℐ_map_ℐ: "eℐ (map_ℐ f g ℐ) = map_ℐ f (apfst g) (eℐ ℐ)"
  by transfer(auto simp add: fun_eq_iff intro: rev_image_eqI)
lemma eℐ_inverse [simp]: "map_ℐ id fst (eℐ ℐ) = ℐ"
  by transfer auto
end
lifting_update ℐ.lifting
lifting_forget ℐ.lifting
section ‹Fused Resource›
subsection ‹Event Oracles -- they generate events›
type_synonym 
  ('state, 'event, 'input, 'output) eoracle = "('state, 'input, 'output × 'event list) oracle'" 
definition
  parallel_eoracle :: "
    ('s1, 'e1, 'i1, 'o1) eoracle ⇒ ('s2, 'e2, 'i2, 'o2) eoracle ⇒
      ('s1 × 's2, 'e1 + 'e2, 'i1 + 'i2, 'o1 + 'o2) eoracle"
  where
    "parallel_eoracle eoracle1 eoracle2 state ≡
       comp
        (map_spmf 
          (map_prod 
            (case_sum 
              (map_prod Inl (map Inl)) 
              (map_prod Inr (map Inr))) 
            id))
        (parallel_oracle eoracle1 eoracle2 state)"
definition
  plus_eoracle :: "
    ('s, 'e1, 'i1, 'o1) eoracle ⇒ ('s, 'e2, 'i2, 'o2) eoracle ⇒
      ('s, 'e1 + 'e2, 'i1 + 'i2, 'o1 + 'o2) eoracle"
  where
    "plus_eoracle eoracle1 eoracle2 state ≡
       comp
        (map_spmf 
          (map_prod 
            (case_sum 
              (map_prod Inl (map Inl)) 
              (map_prod Inr (map Inr))) 
            id))
        (plus_oracle eoracle1 eoracle2 state)"
definition
  translate_eoracle :: "
    ('s_event, 'e1, 'e2 list) oracle' ⇒ ('s_event × 's, 'e1, 'i, 'o) eoracle ⇒
      ('s_event × 's, 'e2, 'i, 'o) eoracle"
  where
    "translate_eoracle translator eoracle state inp ≡ 
      bind_spmf
        (eoracle state inp)
        (λ((out, e_in), s).
          let conc = (λ(es, st) e. map_spmf (map_prod ((@) es) id) (translator st e)) in do {
          (e_out, s_event) ← foldl_spmf conc (return_spmf ([], fst s)) e_in;
          return_spmf ((out, e_out), s_event, snd s)
        })"
subsection ‹Event Handlers -- they absorb (and silently handle) events›
type_synonym
  ('state, 'event) handler = "'state ⇒ 'event ⇒ 'state spmf"
fun
  parallel_handler :: "('s1, 'e1) handler ⇒ ('s2, 'e2) handler ⇒ ('s1 × 's2, 'e1 + 'e2) handler"
  where
    "parallel_handler left _ s (Inl e1) = map_spmf (λs1'. (s1', snd s)) (left (fst s) e1)"
  | "parallel_handler _ right s (Inr e2) = map_spmf (λs2'. (fst s, s2')) (right (snd s) e2)"
definition
  plus_handler :: "('s, 'e1) handler ⇒ ('s, 'e2) handler ⇒ ('s, 'e1 + 'e2) handler"
  where
    "plus_handler left right s ≡ case_sum (left s) (right s)"
lemma parallel_handler_left:
  "map_fun id (map_fun Inl id) (parallel_handler left right) = 
    (λ(s_l, s_r) q. map_spmf (λs_l'. (s_l', s_r)) (left s_l q))"
  by force
lemma parallel_handler_right:
  "map_fun id (map_fun Inr id) (parallel_handler left right) = 
    (λ(s_l, s_r) q. map_spmf (λs_r'. (s_l, s_r')) (right s_r q))"
  by force
lemma in_set_spmf_parallel_handler:
  "s' ∈ set_spmf (parallel_handler left right s x) ⟷
  (case x of Inl e ⇒ fst s' ∈ set_spmf (left (fst s) e) ∧ snd s' = snd s
    | Inr e ⇒ snd s' ∈ set_spmf (right (snd s) e) ∧ fst s' = fst s)"
  by(cases s; cases s'; auto split: sum.split)
subsection ‹Fused Resource Construction›