Theory DBTA_Combine

section ‹Deterministic Büchi Transition Automata Combinations›

theory DBTA_Combine
imports DBTA DGBTA
begin

  (* TODO: exact copy-paste from NBTA, abstract *)
  global_interpretation degeneralization: automaton_degeneralization_run
    dgbta dgbta.alphabet dgbta.initial dgbta.transition dgbta.accepting "λ P w r p. gen infs P (p ## r ||| w ||| r)"
    dbta dbta.alphabet dbta.initial dbta.transition dbta.accepting "λ P w r p. infs P (p ## r ||| w ||| r)"
    id "λ ((p, k), a, (q, l)). ((p, a, q), k)"
    defines degeneralize = degeneralization.degeneralize
  proof
    fix w :: "'a stream"
    fix r :: "'b stream"
    fix cs p k
    let ?f = "λ ((p, k), a, (q, l)). ((p, a, q), k)"
    let ?s = "sscan (count cs  id) (p ## r ||| w ||| r) k"
    have "infs (degen cs  ?f) ((p, k) ## (r ||| ?s) ||| w ||| (r ||| ?s)) 
      infs (degen cs) (smap ?f ((p, k) ## (r ||| ?s) ||| w ||| (r ||| ?s)))"
      by (simp add: comp_def)
    also have "smap ?f ((p, k) ## (r ||| ?s) ||| w ||| (r ||| ?s)) = (p ## r ||| w ||| r) ||| k ## ?s"
      by (coinduction arbitrary: p k r w) (auto simp: eq_scons simp flip: szip_unfold sscan_scons)
    also have " = (p ## r ||| w ||| r) ||| k ## sscan (count cs) (p ## r ||| w ||| r) k" by simp
    also have "infs (degen cs)  = gen infs cs (p ## r ||| w ||| r)" using degen_infs by this
    finally show "infs (degen cs  ?f) ((p, k) ## (r ||| ?s) ||| w ||| (r ||| ?s)) 
      gen infs cs (p ## r ||| w ||| r)" by this
  qed

  lemmas degeneralize_language[simp] = degeneralization.degeneralize_language[folded DBTA.language_def]
  lemmas degeneralize_nodes_finite[iff] = degeneralization.degeneralize_nodes_finite[folded DBTA.nodes_def]
  lemmas degeneralize_nodes_card = degeneralization.degeneralize_nodes_card[folded DBTA.nodes_def]

  global_interpretation intersection: automaton_intersection_run
    dbta.dbta dbta.alphabet dbta.initial dbta.transition dbta.accepting "λ P w r p. infs P (p ## r ||| w ||| r)"
    dbta.dbta dbta.alphabet dbta.initial dbta.transition dbta.accepting "λ P w r p. infs P (p ## r ||| w ||| r)"
    dgbta.dgbta dgbta.alphabet dgbta.initial dgbta.transition dgbta.accepting "λ P w r p. gen infs P (p ## r ||| w ||| r)"
    "λ c1 c2. [c1  (λ ((p1, p2), a, (q1, q2)). (p1, a, q1)), c2  (λ ((p1, p2), a, (q1, q2)). (p2, a, q2))]"
    defines intersect' = intersection.product
  proof
    fix w :: "'a stream"
    fix u :: "'b stream"
    fix v :: "'c stream"
    fix c1 c2 p q
    let ?tfst = "λ ((p1, p2), a, (q1, q2)). (p1, a, q1)"
    let ?tsnd = "λ ((p1, p2), a, (q1, q2)). (p2, a, q2)"
    have "gen infs [c1  ?tfst, c2  ?tsnd] ((p, q) ## (u ||| v) ||| w ||| u ||| v) 
      infs c1 (smap ?tfst ((p, q) ## (u ||| v) ||| w ||| u ||| v)) 
      infs c2 (smap ?tsnd ((p, q) ## (u ||| v) ||| w ||| u ||| v))"
      unfolding gen_def by (simp add: comp_def)
    also have "smap ?tfst ((p, q) ## (u ||| v) ||| w ||| u ||| v) = p ## u ||| w ||| u"
      by (coinduction arbitrary: p q u v w) (auto simp flip: szip_unfold, metis stream.collapse)
    also have "smap ?tsnd ((p, q) ## (u ||| v) ||| w ||| u ||| v) = q ## v ||| w ||| v"
      by (coinduction arbitrary: p q u v w) (auto simp flip: szip_unfold, metis stream.collapse)
    finally show "gen infs [c1  ?tfst, c2  ?tsnd] ((p, q) ## (u ||| v) ||| w ||| u ||| v) 
      infs c1 (p ## u ||| w ||| u)  infs c2 (q ## v ||| w ||| v)" by this
  qed

  lemmas intersect'_language[simp] = intersection.product_language[folded DGBTA.language_def]
  lemmas intersect'_nodes_finite = intersection.product_nodes_finite[folded DGBTA.nodes_def]
  lemmas intersect'_nodes_card = intersection.product_nodes_card[folded DGBTA.nodes_def]

  global_interpretation union: automaton_union_run
    dbta.dbta dbta.alphabet dbta.initial dbta.transition dbta.accepting "λ P w r p. infs P (p ## r ||| w ||| r)"
    dbta.dbta dbta.alphabet dbta.initial dbta.transition dbta.accepting "λ P w r p. infs P (p ## r ||| w ||| r)"
    dbta.dbta dbta.alphabet dbta.initial dbta.transition dbta.accepting "λ P w r p. infs P (p ## r ||| w ||| r)"
    "λ c1 c2 pq. (c1  (λ ((p1, p2), a, (q1, q2)). (p1, a, q1))) pq  (c2  (λ ((p1, p2), a, (q1, q2)). (p2, a, q2))) pq"
    defines union = union.product
  proof
    fix w :: "'a stream"
    fix u :: "'b stream"
    fix v :: "'c stream"
    fix c1 c2 p q
    let ?tfst = "λ ((p1, p2), a, (q1, q2)). (p1, a, q1)"
    let ?tsnd = "λ ((p1, p2), a, (q1, q2)). (p2, a, q2)"
    have "infs (λ pq. (c1  (λ ((p1, p2), a, q1, q2). (p1, a, q1))) pq 
       (c2  (λ ((p1, p2), a, q1, q2). (p2, a, q2))) pq) ((p, q) ## (u ||| v) ||| w ||| (u ||| v))  
      infs c1 (smap ?tfst ((p, q) ## (u ||| v) ||| w ||| u ||| v)) 
      infs c2 (smap ?tsnd ((p, q) ## (u ||| v) ||| w ||| u ||| v))"
      by (simp add: comp_def)
    also have "smap ?tfst ((p, q) ## (u ||| v) ||| w ||| u ||| v) = p ## u ||| w ||| u"
      by (coinduction arbitrary: p q u v w) (auto simp flip: szip_unfold, metis stream.collapse)
    also have "smap ?tsnd ((p, q) ## (u ||| v) ||| w ||| u ||| v) = q ## v ||| w ||| v"
      by (coinduction arbitrary: p q u v w) (auto simp flip: szip_unfold, metis stream.collapse)
    finally show "infs (λ pq. (c1  (λ ((p1, p2), a, q1, q2). (p1, a, q1))) pq 
       (c2  (λ ((p1, p2), a, q1, q2). (p2, a, q2))) pq) ((p, q) ## (u ||| v) ||| w ||| (u ||| v)) 
      infs c1 (p ## u ||| w ||| u)  infs c2 (q ## v ||| w ||| v)" by this
  qed

  lemmas union_language = union.product_language
  lemmas union_nodes_finite = union.product_nodes_finite
  lemmas union_nodes_card = union.product_nodes_card

  abbreviation intersect where "intersect A B  degeneralize (intersect' A B)"

  lemma intersect_language[simp]: "DBTA.language (intersect A B) = DBTA.language A  DBTA.language B"
    by simp
  lemma intersect_nodes_finite:
    assumes "finite (DBTA.nodes A)" "finite (DBTA.nodes B)"
    shows "finite (DBTA.nodes (intersect A B))"
    using intersect'_nodes_finite assms by simp
  lemma intersect_nodes_card:
    assumes "finite (DBTA.nodes A)" "finite (DBTA.nodes B)"
    shows "card (DBTA.nodes (intersect A B))  2 * card (DBTA.nodes A) * card (DBTA.nodes B)"
  proof -
    have "card (DBTA.nodes (intersect A B)) 
      max 1 (length (dgbta.accepting (intersect' A B))) * card (DGBTA.nodes (intersect' A B))"
      using degeneralize_nodes_card by this
    also have "length (dgbta.accepting (intersect' A B)) = 2" by simp
    also have "card (DGBTA.nodes (intersect' A B))  card (DBTA.nodes A) * card (DBTA.nodes B)"
      using intersect'_nodes_card assms by this
    finally show ?thesis by simp
  qed

end