Theory DRA_Translate
section ‹Explore and Enumerate Nodes of Deterministic Rabin Automata›
theory DRA_Translate
imports DRA_Explicit
begin
  subsection ‹Syntax›
  
  no_syntax "_do_let" :: "[pttrn, 'a] ⇒ do_bind" (‹(‹indent=2 notation=‹infix do let››let _ =/ _)› [1000, 13] 13)
  syntax "_do_let" :: "[pttrn, 'a] ⇒ do_bind" (‹(‹indent=2 notation=‹infix do let››let _ =/ _)› 13)
  section ‹Image on Explicit Automata›
  definition drae_image where "drae_image f A ≡ drae (alphabete A) (f (initiale A))
    ((λ (p, a, q). (f p, a, f q)) ` transitione A) (map (map_prod (image f) (image f)) (conditione A))"
  lemma drae_image_param[param]: "(drae_image, drae_image) ∈ (S → T) → ⟨L, S⟩ drae_rel → ⟨L, T⟩ drae_rel"
    unfolding drae_image_def by parametricity
  lemma drae_image_id[simp]: "drae_image id = id" unfolding drae_image_def by auto
  lemma drae_image_dra_drae: "drae_image f (dra_drae A) = drae
    (alphabet A) (f (initial A))
    (⋃ p ∈ nodes A. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p})
    (map (λ (P, Q). (f ` {p ∈ nodes A. P p}, f ` {p ∈ nodes A. Q p})) (condition A))"
    unfolding dra_drae_def drae_image_def drae.simps Set.filter_def by force
  section ‹Exploration and Translation›
  definition trans_spec where
    "trans_spec A f ≡ ⋃ p ∈ nodes A. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}"
  definition trans_algo where
    "trans_algo N L S f ≡
      FOREACH N (λ p T. do {
        ASSERT (p ∈ N);
        FOREACH L (λ a T. do {
          ASSERT (a ∈ L);
          let q = S a p;
          ASSERT ((f p, a, f q) ∉ T);
          RETURN (insert (f p, a, f q) T) }
        ) T }
      ) {}"
  lemma trans_algo_refine:
    assumes "finite (nodes A)" "finite (alphabet A)" "inj_on f (nodes A)"
    assumes "N = nodes A" "L = alphabet A" "S = transition A"
    shows "(trans_algo N L S f, SPEC (HOL.eq (trans_spec A f))) ∈ ⟨Id⟩ nres_rel"
  unfolding trans_algo_def trans_spec_def assms(4-6)
  proof (refine_vcg FOREACH_rule_insert_eq)
    show "finite (nodes A)" using assms(1) by this
    show "(⋃ p ∈ nodes A. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}) =
      (⋃ p ∈ nodes A. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p})" by rule
    show "(⋃ p ∈ {}. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}) = {}" by simp
    fix T x
    assume 1: "T ⊆ nodes A" "x ∈ nodes A" "x ∉ T"
    show "finite (alphabet A)" using assms(2) by this
    show "(⋃ a ∈ {}. f ` {x} × {a} × f ` {transition A a x}) ∪
      (⋃ p ∈ T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}) =
      (⋃ p ∈ T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p})"
      "(⋃ a ∈ alphabet A. f ` {x} × {a} × f ` {transition A a x}) ∪
      (⋃ p ∈ T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}) =
      (⋃ p ∈ insert x T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p})" by auto
    fix Ta xa
    assume 2: "Ta ⊆ alphabet A" "xa ∈ alphabet A" "xa ∉ Ta"
    show "(f x, xa, f (transition A xa x)) ∉ (⋃ a ∈ Ta. f ` {x} × {a} × f ` {transition A a x}) ∪
      (⋃ p ∈ T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p})"
      using 1 2(3) assms(3) by (auto dest: inj_onD)
    show "(⋃ a ∈ insert xa Ta. f ` {x} × {a} × f ` {transition A a x}) ∪
      (⋃ p ∈ T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}) =
      insert (f x, xa, f (transition A xa x)) ((⋃ a ∈ Ta. f ` {x} × {a} × f ` {transition A a x}) ∪
      (⋃ p ∈ T. ⋃ a ∈ alphabet A. f ` {p} × {a} × f ` {transition A a p}))"
      by simp
  qed
  definition to_draei :: "('state, 'label) dra ⇒ ('state, 'label) dra"
    where "to_draei ≡ id"
  
  schematic_goal to_draei_impl:
    fixes S :: "('statei × 'state) set"
    assumes [simp]: "finite (nodes A)"
    assumes [autoref_ga_rules]: "is_bounded_hashcode S seq bhc"
    assumes [autoref_ga_rules]: "is_valid_def_hm_size TYPE('statei) hms"
    assumes [autoref_rules]: "(seq, HOL.eq) ∈ S → S → bool_rel"
    assumes [autoref_rules]: "(Ai, A) ∈ ⟨L, S⟩ drai_dra_rel"
    shows "(?f :: ?'a, do {
        let N = nodes A;
        f ← op_set_enumerate N;
        ASSERT (dom f = N);
        ASSERT (f (initial A) ≠ None);
        ASSERT (∀ a ∈ alphabet A. ∀ p ∈ dom f. f (transition A a p) ≠ None);
        T ← trans_algo N (alphabet A) (transition A) (λ x. the (f x));
        RETURN (drae (alphabet A) ((λ x. the (f x)) (initial A)) T
          (map (λ (P, Q). ((λ x. the (f x)) ` {p ∈ N. P p}, (λ x. the (f x)) ` {p ∈ N. Q p})) (condition A)))
      }) ∈ ?R"
    unfolding trans_algo_def by (autoref_monadic (plain))
  concrete_definition to_draei_impl uses to_draei_impl
  lemma to_draei_impl_refine'':
    fixes S :: "('statei × 'state) set"
    assumes "finite (nodes A)"
    assumes "is_bounded_hashcode S seq bhc"
    assumes "is_valid_def_hm_size TYPE('statei) hms"
    assumes "(seq, HOL.eq) ∈ S → S → bool_rel"
    assumes "(Ai, A) ∈ ⟨L, S⟩ drai_dra_rel"
    shows "(RETURN (to_draei_impl seq bhc hms Ai), do {
        f ← op_set_enumerate (nodes A);
        RETURN (drae_image (the ∘ f) (dra_drae A))
      }) ∈ ⟨⟨L, nat_rel⟩ draei_drae_rel⟩ nres_rel"
  proof -
    have 1: "finite (alphabet A)"
      using drai_dra_param(2)[param_fo, OF assms(5)] list_set_rel_finite
      unfolding finite_set_rel_def by auto
    note to_draei_impl.refine[OF assms]
    also have "(do {
        let N = nodes A;
        f ← op_set_enumerate N;
        ASSERT (dom f = N);
        ASSERT (f (initial A) ≠ None);
        ASSERT (∀ a ∈ alphabet A. ∀ p ∈ dom f. f (transition A a p) ≠ None);
        T ← trans_algo N (alphabet A) (transition A) (λ x. the (f x));
        RETURN (drae (alphabet A) ((λ x. the (f x)) (initial A)) T
          (map (λ (P, Q). ((λ x. the (f x)) ` {p ∈ N. P p}, (λ x. the (f x)) ` {p ∈ N. Q p})) (condition A)))
      }, do {
        f ← op_set_enumerate (nodes A);
        T ← SPEC (HOL.eq (trans_spec A (λ x. the (f x))));
        RETURN (drae (alphabet A) ((λ x. the (f x)) (initial A)) T
          (map (λ (P, Q). ((λ x. the (f x)) ` {p ∈ nodes A. P p}, (λ x. the (f x)) ` {p ∈ nodes A. Q p})) (condition A)))
      }) ∈ ⟨Id⟩ nres_rel"
      unfolding Let_def comp_apply op_set_enumerate_def using assms(1) 1
      by (refine_vcg vcg0[OF trans_algo_refine]) (auto intro!: inj_on_map_the[unfolded comp_apply])
    also have "(do {
        f ← op_set_enumerate (nodes A);
        T ← SPEC (HOL.eq (trans_spec A (λ x. the (f x))));
        RETURN (drae (alphabet A) ((λ x. the (f x)) (initial A)) T
          (map (λ (P, Q). ((λ x. the (f x)) ` {p ∈ nodes A. P p}, (λ x. the (f x)) ` {p ∈ nodes A. Q p})) (condition A)))
      },  do {
        f ← op_set_enumerate (nodes A);
        RETURN (drae_image (the ∘ f) (dra_drae A))
      }) ∈ ⟨Id⟩ nres_rel"
      unfolding trans_spec_def drae_image_dra_drae by refine_vcg force
    finally show ?thesis unfolding nres_rel_comp by simp
  qed
  
  context
    fixes Ai A
    fixes seq bhc hms
    fixes S :: "('statei × 'state) set"
    assumes a: "finite (nodes A)"
    assumes b: "is_bounded_hashcode S seq bhc"
    assumes c: "is_valid_def_hm_size TYPE('statei) hms"
    assumes d: "(seq, HOL.eq) ∈ S → S → bool_rel"
    assumes e: "(Ai, A) ∈ ⟨Id, S⟩ drai_dra_rel"
  begin
    definition f' where "f' ≡ SOME f'.
      (to_draei_impl seq bhc hms Ai, drae_image (the ∘ f') (dra_drae A)) ∈ ⟨Id, nat_rel⟩ draei_drae_rel ∧
      dom f' = nodes A ∧ inj_on f' (nodes A)"
    lemma 1: "∃ f'. (to_draei_impl seq bhc hms Ai, drae_image (the ∘ f') (dra_drae A)) ∈
      ⟨Id, nat_rel⟩ draei_drae_rel ∧ dom f' = nodes A ∧ inj_on f' (nodes A)"
      using to_draei_impl_refine''[
        OF a b c d e,
        unfolded op_set_enumerate_def bind_RES_RETURN_eq,
        THEN nres_relD,
        THEN RETURN_ref_SPECD]
      by force
    lemma f'_refine: "(to_draei_impl seq bhc hms Ai, drae_image (the ∘ f') (dra_drae A)) ∈
      ⟨Id, nat_rel⟩ draei_drae_rel" using someI_ex[OF 1, folded f'_def] by auto
    lemma f'_dom: "dom f' = nodes A" using someI_ex[OF 1, folded f'_def] by auto
    lemma f'_inj: "inj_on f' (nodes A)" using someI_ex[OF 1, folded f'_def] by auto
    definition f where "f ≡ the ∘ f'"
    definition g where "g = inv_into (nodes A) f"
    lemma inj_f[intro!, simp]: "inj_on f (nodes A)"
      using f'_inj f'_dom unfolding f_def by (simp add: inj_on_map_the)
    lemma inj_g[intro!, simp]: "inj_on g (f ` nodes A)"
      unfolding g_def by (simp add: inj_on_inv_into)
    definition rel where "rel ≡ {(f p, p) |p. p ∈ nodes A}"
    lemma rel_alt_def: "rel = (br f (λ p. p ∈ nodes A))¯"
      unfolding rel_def by (auto simp: in_br_conv)
    lemma rel_inv_def: "rel = br g (λ k. k ∈ f ` nodes A)"
      unfolding rel_alt_def g_def by (auto simp: in_br_conv)
    lemma rel_domain[simp]: "Domain rel = f ` nodes A" unfolding rel_def by force
    lemma rel_range[simp]: "Range rel = nodes A" unfolding rel_def by auto
    lemma [intro!, simp]: "bijective rel" unfolding rel_inv_def by (simp add: bijective_alt)
    lemma [simp]: "Id_on (f ` nodes A) O rel = rel" unfolding rel_def by auto
    lemma [simp]: "rel O Id_on (nodes A) = rel" unfolding rel_def by auto
    lemma [param]: "(f, f) ∈ Id_on (Range rel) → Id_on (Domain rel)" unfolding rel_alt_def by auto
    lemma [param]: "(g, g) ∈ Id_on (Domain rel) → Id_on (Range rel)" unfolding rel_inv_def by auto
    lemma [param]: "(id, f) ∈ rel → Id_on (Domain rel)" unfolding rel_alt_def by (auto simp: in_br_conv)
    lemma [param]: "(f, id) ∈ Id_on (Range rel) → rel" unfolding rel_alt_def by (auto simp: in_br_conv)
    lemma [param]: "(id, g) ∈ Id_on (Domain rel) → rel" unfolding rel_inv_def by (auto simp: in_br_conv)
    lemma [param]: "(g, id) ∈ rel → Id_on (Range rel)" unfolding rel_inv_def by (auto simp: in_br_conv)
    lemma to_draei_impl_refine':
      "(to_draei_impl seq bhc hms Ai, to_draei A) ∈ ⟨Id_on (alphabet A), rel⟩ draei_dra_rel"
    proof -
      have 1: "(draei_drae (to_draei_impl seq bhc hms Ai), id (drae_image f (dra_drae A))) ∈
        ⟨Id, nat_rel⟩ drae_rel" using f'_refine[folded f_def] by parametricity
      have 2: "(draei_drae (to_draei_impl seq bhc hms Ai), id (drae_image f (dra_drae A))) ∈
        ⟨Id_on (alphabet A), Id_on (f ` nodes A)⟩ drae_rel"
        using 1 unfolding drae_rel_def dra_drae_def drae_image_def by auto
      have 3: "wft (alphabet A) (nodes A) (transitione (dra_drae A))"
        using wft_transitions unfolding dra_drae_def drae.sel by this
      have 4: "(wft (alphabet A) (f ` nodes A) (transitione (drae_image f (dra_drae A))),
        wft (alphabet A) (id ` nodes A) (transitione (drae_image id (dra_drae A)))) ∈ bool_rel"
        using dra_rel_eq by parametricity auto
      have 5: "wft (alphabet A) (f ` nodes A) (transitione (drae_image f (dra_drae A)))" using 3 4 by simp
      have "(drae_dra (draei_drae (to_draei_impl seq bhc hms Ai)), drae_dra (id (drae_image f (dra_drae A)))) ∈
        ⟨Id_on (alphabet A), Id_on (f ` nodes A)⟩ dra_rel" using 2 5 by parametricity auto
      also have "(drae_dra (id (drae_image f (dra_drae A))), drae_dra (id (drae_image id (dra_drae A)))) ∈
        ⟨Id_on (alphabet A), rel⟩ dra_rel" using dra_rel_eq 3 by parametricity auto
      also have "drae_dra (id (drae_image id (dra_drae A))) = (drae_dra ∘ dra_drae) A" by simp
      also have "(…, id A) ∈ ⟨Id_on (alphabet A), Id_on (nodes A)⟩ dra_rel" by parametricity
      also have "id A = to_draei A" unfolding to_draei_def by simp
      finally show ?thesis unfolding draei_dra_rel_def by simp
    qed
  end
  context
  begin
    interpretation autoref_syn by this
    lemma to_draei_impl_refine[autoref_rules]:
      fixes S :: "('statei × 'state) set"
      assumes "SIDE_PRECOND (finite (nodes A))"
      assumes "SIDE_GEN_ALGO (is_bounded_hashcode S seq bhc)"
      assumes "SIDE_GEN_ALGO (is_valid_def_hm_size TYPE('statei) hms)"
      assumes "GEN_OP seq HOL.eq (S → S → bool_rel)"
      assumes "(Ai, A) ∈ ⟨Id, S⟩ drai_dra_rel"
      shows "(to_draei_impl seq bhc hms Ai,
        (OP to_draei ::: ⟨Id, S⟩ drai_dra_rel →
        ⟨Id_on (alphabet A), rel Ai A seq bhc hms⟩ draei_dra_rel) $ A) ∈
        ⟨Id_on (alphabet A), rel Ai A seq bhc hms⟩ draei_dra_rel"
      using to_draei_impl_refine' assms unfolding autoref_tag_defs by this
  end
end