Theory AbsAlgo

(*  Title:       Tree Automata
    Author:      Peter Lammich <peter dot lammich at uni-muenster.de>
    Maintainer:  Peter Lammich <peter dot lammich at uni-muenster.de>
*)
section "Abstract Tree Automata Algorithms"
theory AbsAlgo
imports 
  Ta 
  Collections_Examples.Exploration
  Collections.CollectionsV1
begin

no_notation fun_rel_syn (infixr "" 60)

text_raw ‹\label{sec:absalgo}›
text ‹This theory defines tree automata algorithms on an abstract level, 
  that is using non-executable datatypes and constructs like sets, 
  set-collecting operations, etc. 
    
  These algorithms are then refined to executable algorithms in 
  Section~\ref{sec:taimpl}.
›

subsection ‹Word Problem›
  
text ‹
  First, a recursive version of the @{const accs}-predicate is defined.
›

fun r_match :: "'a set list  'a list  bool" where
  "r_match [] []  True" |
  "r_match (A#AS) (a#as)  aA  r_match AS as" |
  "r_match _ _  False"

― ‹@{const r_match} accepts two lists, if they have the same length and 
  the elements in the second list are contained in the respective 
  elements of the first list:›
lemma r_match_alt: 
  "r_match L l  length L = length l  (i<length l. l!i  L!i)"
  apply (induct L l rule: r_match.induct)
  apply auto
  apply (case_tac i)
  apply auto
  done

― ‹Whether a rule matches the given state, label and list of sets of states›
fun r_matchc where
  "r_matchc q l Qs (qr  lr qsr)  q=qr  l=lr  r_match Qs qsr"

― ‹recursive version of @{const accs}-predicate›  
fun faccs :: "('Q,'L) ta_rule set  'L tree  'Q set" where
  "faccs δ (NODE f ts) = (
    let Qs = map (faccs δ) (ts) in
      {q. rδ. r_matchc q f Qs r }
  )"

lemma faccs_correct_aux: 
  "qfaccs δ n = accs δ n q" (is ?T1)
  "(map (faccs δ) ts = map (λt. { q . accs δ t q}) ts)" (is ?T2)
proof -
  have "(q. qfaccs δ n = accs δ n q) 
         (map (faccs δ) ts = map (λt. { q . accs δ t q}) ts)"
  proof (induct rule: compat_tree_tree_list.induct)
    case (NODE f ts)
    thus ?case
      apply (intro allI iffI)
      apply simp
      apply (erule bexE)
      apply (case_tac x)
      apply simp
      apply (rule accs.intros)
      apply assumption
      apply (unfold r_match_alt)
      apply simp
      apply fastforce
      apply simp
      apply (erule accs.cases)
      apply auto
      apply (rule_tac x="qa  f qs" in bexI)
      apply simp
      apply (unfold r_match_alt)
      apply auto
      done
  qed auto
  thus ?T1 ?T2 by auto
qed

theorem faccs_correct1: "qfaccs δ n  accs δ n q" 
  by (simp add: faccs_correct_aux)
theorem faccs_correct2: "accs δ n q  qfaccs δ n" 
  by (simp add: faccs_correct_aux)

lemmas faccs_correct = faccs_correct1 faccs_correct2

lemma faccs_alt: "faccs δ t = {q. accs δ t q}" by (auto intro: faccs_correct)

subsection ‹Backward Reduction and Emptiness Check›
subsubsection "Auxiliary Definitions"

― ‹Step function, that maps a set of states to those states 
  that are reachable via one backward step.›
inductive_set bacc_step :: "('Q,'L) ta_rule set  'Q set  'Q set" 
  for δ Q 
  where
  " rδ; set (rhsq r)  Q   lhs r  bacc_step δ Q"

― ‹If a set is closed under adding all states that are reachable from the set 
  by one backward step, then this set contains all backward accessible states.›
lemma b_accs_as_closed:
  assumes A: "bacc_step δ Q  Q"  
  shows "b_accessible δ  Q"
proof (rule subsetI)
  fix q
  assume "qb_accessible δ"
  thus "qQ" 
  proof (induct rule: b_accessible.induct)
    fix q f qs
    assume BC: "(qf qs)δ" 
               "!!x. xset qs  xb_accessible δ" 
               "!!x. xset qs  xQ"
    from bacc_step.intros[OF BC(1)] BC(3) have "qbacc_step δ Q" by auto
    with A show "qQ" by blast
  qed
qed

subsubsection "Algorithms"

text ‹
  First, the basic workset algorithm is specified. 
  Then, it is refined to contain a counter for each rule, 
  that counts the number of undiscovered states on the RHS. 
  For both levels of abstraction, a version that computes the 
  backwards reduction, and a version that checks for emptiness is specified.

  Additionally, a version of the algorithm that computes a witness
  for non-emptiness is provided.
  
  Levels of abstraction:
  \begin{itemize} 
    \item[α›] On this level, the state consists of a set of 
      discovered states and a workset.
    \item[α'›] On this level, the state consists of a set of 
      discovered states, a workset and a map from rules to number of 
      undiscovered rhs states. This map can be used to make the discovery of
      rules that have to be considered more efficient.
  \end{itemize}
›

text_raw ‹\paragraph {α› - Level:}›

  ― ‹A state contains the set of discovered states and a workset›
type_synonym ('Q,'L) br_state = "'Q set × 'Q set"

  ― ‹Set of states that are non-empty (accept a tree) after adding the 
  state $q$ to the set of discovered states›
definition br_dsq 
  :: "('Q,'L) ta_rule set  'Q  ('Q,'L) br_state  'Q set" 
  where  
  "br_dsq δ q == λ(Q,W). { lhs r | r. rδ  set (rhsq r)  (Q-(W-{q})) }"

  ― ‹Description of a step: One state is removed from the workset, and all 
  new states that become non-empty due to this state are added to, both, 
  the workset and the set of discovered states›
inductive_set br_step 
  :: "('Q,'L) ta_rule set  (('Q,'L) br_state × ('Q,'L) br_state) set" 
  for δ where
  "
     qW;
     Q' = Q  br_dsq δ q (Q,W);
     W' = W - {q}  (br_dsq δ q (Q,W) - Q)
     ((Q,W),(Q',W'))br_step δ"

  ― ‹Termination condition for backwards reduction: The workset is empty›
definition br_cond :: "('Q,'L) br_state set" 
  where "br_cond == {(Q,W). W{}}"

  ― ‹Termination condition for emptiness check: 
      The workset is empty or a non-empty initial state has been discovered›
definition bre_cond :: "'Q set  ('Q,'L) br_state set" 
  where "bre_cond Qi == {(Q,W). W{}  (QiQ={})}"

  ― ‹Set of all states that occur on the lhs of a constant-rule›
definition br_iq :: "('Q,'L) ta_rule set  'Q set" 
  where "br_iq δ == { lhs r | r. rδ  rhsq r = [] }"

  ― ‹Initial state for the iteration›
definition br_initial :: "('Q,'L) ta_rule set  ('Q,'L) br_state" 
  where "br_initial δ == (br_iq δ, br_iq δ)"

  ― ‹Invariant for the iteration: 
    \begin{itemize}
      \item States on the workset have been discovered
      \item Only accessible states have been discovered
      \item If a state is non-empty due to a rule whose 
            rhs-states have been discovered and processed 
            (i.e. are in $Q-W$), then the lhs state of the 
            rule has also been discovered.
      \item The set of discovered states is finite
    \end{itemize}›
definition br_invar :: "('Q,'L) ta_rule set  ('Q,'L) br_state set" 
  where "br_invar δ == {(Q,W). 
    WQ  
    Q  b_accessible δ  
    bacc_step δ (Q - W)  Q  
    finite Q}"

definition "br_algo δ == 
  wa_cond = br_cond,
  wa_step = br_step δ,
  wa_initial = {br_initial δ},
  wa_invar = br_invar δ
"

definition "bre_algo Qi δ == 
  wa_cond = bre_cond Qi,
  wa_step = br_step δ,
  wa_initial = {br_initial δ},
  wa_invar = br_invar δ
"


  ― ‹Termination: Either a new state is added, or the workset decreases.›
definition "br_termrel δ == 
  ({(Q',Q). Q  Q'  Q'  b_accessible δ}) <*lex*> finite_psubset"

lemma bre_cond_imp_br_cond[intro, simp]: "bre_cond Qi  br_cond" 
  by (auto simp add: br_cond_def bre_cond_def)

lemma br_termrel_wf[simp, intro!]: "finite δ  wf (br_termrel δ)"
  apply (unfold br_termrel_def)
  apply (auto simp add: wf_bounded_supset)
  done

  ― ‹Only accessible states are discovered›
lemma br_dsq_ss:
  assumes A: "(Q,W)br_invar δ" "W  {}" "qW"
  shows "br_dsq δ q (Q,W)  b_accessible δ"
proof (rule subsetI)
  fix q'
  assume B: "q'br_dsq δ q (Q,W)"
  then obtain r where 
    R: "q' = lhs r" "rδ" and 
    S: "set (rhsq r)  (Q-(W-{q}))" 
    by (unfold br_dsq_def) auto
  note S
  also have "(Q-(W-{q}))  b_accessible δ" using A(1,3)
    by (auto simp add: br_invar_def)
  finally show "q'b_accessible δ" using R
    by (cases r)
  (auto intro: b_accessible.intros)
qed

lemma br_step_in_termrel: 
  assumes A: "Σbr_cond" "Σbr_invar δ" "(Σ,Σ')br_step δ"
  shows "(Σ', Σ)br_termrel δ"
proof -
  obtain Q W Q' W' where 
    [simp]: "Σ=(Q,W)" "Σ'=(Q',W')" 
    by (cases Σ, cases Σ', auto)
  obtain q where 
    QIW: "qW" and 
    ASSFMT[simp]: "Q' = Q  br_dsq δ q (Q, W)"
                  "W' = W - {q}  (br_dsq δ q (Q, W) - Q)"
    by (auto intro: br_step.cases[OF A(3)[simplified]])

  from A(2) have [simp]: "finite Q" 
    by (auto simp add: br_invar_def)
  from A(2)[unfolded br_invar_def] have [simp]: "finite W" 
    by (auto simp add: finite_subset)
  from A(1) have WNE: "W{}" by (unfold br_cond_def) auto

  note DSQSS = br_dsq_ss[OF A(2)[simplified] WNE QIW]
  {
    assume "br_dsq δ q (Q,W) - Q = {}"
    hence ?thesis using QIW
      by (simp add: br_termrel_def set_simps)
  } moreover {
    assume "br_dsq δ q (Q,W) - Q  {}"
    hence "Q  Q'" by auto
    moreover from DSQSS A(2)[unfolded br_invar_def] have 
      "Q'  b_accessible δ" 
      by auto
    ultimately have ?thesis 
      by (auto simp add: br_termrel_def)
  } ultimately show ?thesis by blast
qed

lemma br_invar_initial[simp]: "finite δ  (br_initial δ)br_invar δ"
  apply (auto simp add: br_initial_def br_invar_def br_iq_def)
    
  apply (case_tac r)
  apply (fastforce intro: b_accessible.intros)
  apply (fastforce elim!: bacc_step.cases)
  done

lemma br_invar_step: 
  assumes [simp]: "finite δ"
  assumes A: "Σbr_cond" "Σbr_invar δ" "(Σ,Σ')br_step δ"
  shows "Σ'br_invar δ"
proof -
  obtain Q W Q' W' where SF[simp]: "Σ=(Q,W)" "Σ'=(Q',W')" 
    by (cases Σ, cases Σ', auto)
  obtain q where 
    QIW: "qW" and 
    ASSFMT[simp]: "Q' = Q  br_dsq δ q (Q, W)"
                  "W' = W - {q}  (br_dsq δ q (Q, W) - Q)"
    by (auto intro: br_step.cases[OF A(3)[simplified]])

  from A(1) have WNE: "W{}" by (unfold br_cond_def) auto

  have DSQSS: "br_dsq δ q (Q,W)  b_accessible δ"
    using br_dsq_ss[OF A(2)[simplified] WNE QIW] .

  show ?thesis
    apply (simp add: br_invar_def del: ASSFMT)
  proof (intro conjI)
    from A(2) have "W  Q" by (simp add: br_invar_def)
    thus "W'  Q'" by auto
  next
    from A(2) have "Q  b_accessible δ" by (simp add: br_invar_def)
    with DSQSS show "Q'  b_accessible δ" by auto
  next
    show "bacc_step δ (Q' - W')  Q'"
      apply (rule subsetI)
      apply (erule bacc_step.cases)
      apply (auto simp add: br_dsq_def)
      done
  next
    show "finite Q'" using A(2) by (simp add: br_invar_def br_dsq_def)
  qed
qed


lemma br_invar_final:
  "Σ. Σwa_invar (br_algo δ)  Σwa_cond (br_algo δ) 
    fst Σ = b_accessible δ"
  apply (simp add: br_invar_def br_cond_def br_algo_def)
  apply (auto intro: rev_subsetD[OF _ b_accs_as_closed])
  done
(*  shows "⟦(Q,W)∈br_invar δ; (Q,W)∉br_cond⟧ ⟹ Q = b_accessible δ"
  apply (simp add: br_invar_def br_cond_def)
  apply (auto intro: rev_subsetD[OF _ b_accs_as_closed])
  done*)

theorem br_while_algo: 
  assumes FIN[simp]: "finite δ"
  shows "while_algo (br_algo δ)"
  apply (unfold_locales)
  apply (simp_all add: br_algo_def br_invar_step br_invar_initial 
                       br_step_in_termrel)
  apply (rule_tac r="br_termrel δ" in wf_subset)
  apply (auto intro: br_step_in_termrel)
  done

lemma bre_invar_final:
  "Σ. Σwa_invar (bre_algo Qi δ)  Σwa_cond (bre_algo Qi δ) 
      ((Qifst Σ={})  (Qi  b_accessible δ = {}))"
  apply (simp add: br_invar_def bre_cond_def bre_algo_def)
  apply safe
  apply (auto dest!: b_accs_as_closed)
  done

theorem bre_while_algo:
  assumes FIN[simp]: "finite δ"
  shows "while_algo (bre_algo Qi δ)"
  apply (unfold_locales)
  apply (unfold bre_algo_def)
  apply (auto simp add: br_invar_initial br_step_in_termrel
    intro: br_invar_step 
    dest: rev_subsetD[OF _ bre_cond_imp_br_cond])
  apply (rule_tac r="br_termrel δ" in wf_subset)
  apply (auto intro: br_step_in_termrel
              dest: rev_subsetD[OF _ bre_cond_imp_br_cond])
  done

text_raw ‹\paragraph{α'› - Level}›
text ‹
  Here, an optimization is added:
    For each rule, the algorithm now maintains a counter that counts the number
    of undiscovered states on the rules RHS. Whenever a new state is discovered,
    this counter is decremented for all rules where the state occurs on the RHS.
    The LHS states of rules where the counter falls to 0 are added to the 
    worklist. The idea is that decrementing the counter is more efficient than 
    checking whether all states on the rule's RHS have been discovered.

  A similar algorithm is sketched in cite"tata2007"(Exercise~1.18).
›
type_synonym ('Q,'L) br'_state = "'Q set × 'Q set × (('Q,'L) ta_rule  nat)"

  ― ‹Abstraction to @{text α}-level›
definition br'_α :: "('Q,'L) br'_state  ('Q,'L) br_state" 
  where "br'_α = (λ(Q,W,rcm). (Q,W))"

definition br'_invar_add :: "('Q,'L) ta_rule set  ('Q,'L) br'_state set"
  where "br'_invar_add δ == {(Q,W,rcm). 
    (rδ. rcm r = Some (card (set (rhsq r) - (Q - W))))  
    {lhs r | r. rδ  the (rcm r) = 0}  Q
  }"

definition br'_invar :: "('Q,'L) ta_rule set  ('Q,'L) br'_state set"
  where "br'_invar δ == br'_invar_add δ  {Σ. br'_α Σ  br_invar δ}"

inductive_set br'_step 
  :: "('Q,'L) ta_rule set  (('Q,'L) br'_state × ('Q,'L) br'_state) set" 
  for δ where
  " qW;
     Q' = Q  { lhs r | r. rδ  q  set (rhsq r)  the (rcm r)  1 };
     W' = (W-{q}) 
           ({ lhs r | r. rδ  q  set (rhsq r)  the (rcm r)  1 } 
              - Q);
     !!r. rδ  rcm' r = ( if q  set (rhsq r) then 
                               Some (the (rcm r) - 1) 
                             else rcm r
                           )
     ((Q,W,rcm),(Q',W',rcm'))  br'_step δ"

definition br'_cond :: "('Q,'L) br'_state set" 
  where "br'_cond == {(Q,W,rcm). W{}}"
definition bre'_cond :: "'Q set  ('Q,'L) br'_state set" 
  where "bre'_cond Qi == {(Q,W,rcm). W{}  (QiQ={})}"

inductive_set br'_initial :: "('Q,'L) ta_rule set  ('Q,'L) br'_state set" 
  for δ where
  " !!r. rδ  rcm r = Some (card (set (rhsq r)))  
      (br_iq δ, br_iq δ, rcm)br'_initial δ"

definition "br'_algo δ == 
  wa_cond=br'_cond,
  wa_step = br'_step δ,
  wa_initial = br'_initial δ,
  wa_invar = br'_invar δ
"

definition "bre'_algo Qi δ == 
  wa_cond=bre'_cond Qi,
  wa_step = br'_step δ,
  wa_initial = br'_initial δ,
  wa_invar = br'_invar δ
"

lemma br'_step_invar: 
  assumes finite[simp]: "finite δ"
  assumes INV: "Σbr'_invar_add δ" "br'_α Σ  br_invar δ"
  assumes STEP: "(Σ,Σ')  br'_step δ"
  shows "Σ'br'_invar_add δ"
proof -
  obtain Q W rcm where [simp]: "Σ=(Q,W,rcm)"
    by (cases Σ) auto
  obtain Q' W' rcm' where [simp]: "Σ'=(Q',W',rcm')"
    by (cases Σ') auto

  from STEP obtain q where
    STEPF:
    "qW"
    "Q' = Q  { lhs r | r. rδ  q  set (rhsq r)  the (rcm r)  1 }"
    "W' = (W-{q}) 
           ({ lhs r | r. rδ  q  set (rhsq r)  the (rcm r)  1 } 
              - Q)"
    "!!r. rδ  rcm' r = ( if q  set (rhsq r) then 
                               Some (the (rcm r) - 1) 
                             else rcm r
                           )"
    by (auto elim: br'_step.cases)

  from INV[unfolded br'_invar_def br_invar_def br'_invar_add_def br'_α_def, 
           simplified] 
  have INV:
    "(rδ. rcm r = Some (card (set (rhsq r) - (Q - W))))" 
    "{lhs r |r. r  δ  the (rcm r) = 0}  Q" 
    "W  Q" 
    "Q  b_accessible δ" 
    "bacc_step δ (Q - W)  Q" 
    "finite Q"
    by auto

  {
    fix r
    assume A: "rδ"
    with INV(1) have RCMR: "rcm r = Some (card (set (rhsq r) - (Q - W)))" 
      by auto

    have "rcm' r = Some (card (set (rhsq r) - (Q' - W')))"
    proof (cases "qset (rhsq r)")
      case False
      with A STEPF(4) have "rcm' r = rcm r" by auto
      moreover from STEPF INV(3) False have 
        "set (rhsq r) - (Q-W) = set (rhsq r) - (Q'-W')" 
        by auto
      ultimately show ?thesis
        by (simp add: RCMR)
    next
      case True
      with A STEPF(4) RCMR have 
        "rcm' r = Some ((card (set (rhsq r) - (Q - W))) - 1)"
        by simp
      moreover from STEPF INV(3) True have 
        "set (rhsq r) - (Q-W) = insert q (set (rhsq r) - (Q'-W'))"
        "q(set (rhsq r) - (Q'-W'))"
        by auto
      ultimately show ?thesis
        by (simp add: RCMR card_insert_disjoint')
    qed
  } moreover {
    fix r
    assume A: "rδ" "the (rcm' r) = 0"
    have "lhs r  Q'" proof (cases "qset (rhsq r)")
      case True
      with A(1) STEPF(4) have "rcm' r = Some (the (rcm r) - 1)" by auto
      with A(2) have "the (rcm r) - 1 = 0" by auto
      hence "the (rcm r)  1" by auto
      with STEPF(2) A(1) True show ?thesis by auto
    next
      case False
      with A(1) STEPF(4) have "rcm' r = rcm r" by auto
      with A(2) have "the (rcm r) = 0" by auto
      with A(1) INV(2) have "lhs r  Q" by auto
      with STEPF(2) show ?thesis by auto
    qed
  } ultimately show ?thesis
    by (auto simp add: br'_invar_add_def)
qed

lemma br'_invar_initial: 
  "br'_initial δ  br'_invar_add δ"
  apply safe
  apply (erule br'_initial.cases)
  apply (unfold br'_invar_add_def)
  apply (auto simp add: br_iq_def)
  done

lemma br'_rcm_aux': 
  " (Q,W,rcm)br'_invar δ; qW  
     {r  δ. q  set (rhsq r)  the (rcm r)  Suc 0} 
         = {rδ. qset (rhsq r)  set (rhsq r)  (Q - (W-{q}))}"
proof (intro subsetI equalityI, goal_cases)
  case prems: (1 r)
  hence  B: "rδ" "qset (rhsq r)" "the (rcm r)  Suc 0" by auto
  from B(1,3) prems(1)[unfolded br'_invar_def br'_invar_add_def] have 
    CARD: "card (set (rhsq r) - (Q - W))  Suc 0" 
    by auto
  from prems(1)[unfolded br'_invar_def br_invar_def br'_α_def] have WSQ: "WQ" 
    by auto
  have "set (rhsq r) - (Q - W) = {q}" 
  proof -
    from B(2) prems(2) have R1: "qset (rhsq r) - (Q - W)" by auto
    moreover
    {
      fix x
      assume A: "xq" "xset (rhsq r) - (Q - W)"
      with R1 have "{x,q}  set (rhsq r) - (Q - W)" by auto
      hence "card {x,q}  card (set (rhsq r) - (Q - W))" 
        by (auto simp add: card_mono)
      with CARD A(1) have False by auto
    }
    ultimately show ?thesis by auto
  qed
  with prems(2) WSQ have "set (rhsq r)  Q - (W - {q})" by auto
  thus ?case using B(1,2) by auto 
next
  case prems: (2 r)
  hence B: "rδ" "qset (rhsq r)" "set (rhsq r)  Q - (W - {q})" by auto
  with prems(1)[unfolded br'_invar_def br'_invar_add_def 
                         br'_α_def br_invar_def] 
  have 
    IC: "WQ" "the (rcm r) = card (set (rhsq r) - (Q - W))" 
    by auto
  have "set (rhsq r) - (Q - W)  {q}" using B(2,3) IC(1) by auto
  from card_mono[OF _ this] have "the (rcm r)  Suc 0" by (simp add: IC(2))
  with B(1,2) show ?case by auto
qed

lemma br'_rcm_aux: 
  assumes A: "(Q,W,rcm)br'_invar δ" "qW"  
  shows "{lhs r |r. r  δ  q  set (rhsq r)  the (rcm r)  Suc 0} 
         = {lhs r | r. rδ  qset (rhsq r)  set (rhsq r)  (Q - (W-{q}))}"
proof -
  have "{lhs r |r. r  δ  q  set (rhsq r)  the (rcm r)  Suc 0} 
        = lhs ` {r  δ. q  set (rhsq r)  the (rcm r)  Suc 0}" 
    by auto
  also from br'_rcm_aux'[OF A] have 
    " = lhs ` {r  δ. q  set (rhsq r)  set (rhsq r)  Q - (W - {q})}" 
    by simp
  also have 
    " = {lhs r | r. rδ  qset (rhsq r)  set (rhsq r)  (Q - (W-{q}))}" 
    by auto
  finally show ?thesis .
qed
  
lemma br'_invar_QcD: 
  "(Q,W,rcm)  br'_invar δ  {lhs r | r. rδ  set (rhsq r)  (Q-W)}  Q"
proof (safe)
  fix r
  assume A: "(Q,W,rcm)br'_invar δ" "rδ" "set (rhsq r)  Q - W"
  from A(1)[unfolded br'_invar_def br'_invar_add_def br'_α_def br_invar_def, 
            simplified] 
  have 
    IC: "W  Q" 
        "finite Q" 
        "(rδ. rcm r = Some (card (set (rhsq r) - (Q - W))))" 
        "{lhs r |r. r  δ  the (rcm r) = 0}  Q" by auto
  from IC(3) A(2,3) have "the (rcm r) = 0" by auto
  with IC(4) A(2) show "lhs r  Q" by auto
qed

lemma br'_rcm_aux2: 
  " (Q,W,rcm)br'_invar δ; qW  
     Q  br_dsq δ q (Q,W) 
        = Q  {lhs r |r. r  δ  q  set (rhsq r)  the (rcm r)  Suc 0}"
  apply (simp only: br'_rcm_aux)
  apply (unfold br_dsq_def)
  apply simp
  apply (frule br'_invar_QcD)
  apply auto
  done

lemma br'_rcm_aux3: 
  " (Q,W,rcm)br'_invar δ; qW  
     br_dsq δ q (Q,W) - Q 
        = {lhs r |r. r  δ  q  set (rhsq r)  the (rcm r)  Suc 0} - Q"
  apply (simp only: br'_rcm_aux)
  apply (unfold br_dsq_def)
  apply simp
  apply (frule br'_invar_QcD)
  apply auto
  done

lemma br'_step_abs: 
  " 
     Σbr'_invar δ; 
     (Σ,Σ')  br'_step δ 
     (br'_α Σ, br'_α Σ')br_step δ"
  apply (cases Σ, cases Σ', simp)
  apply (erule br'_step.cases)
  apply (simp add: br'_α_def)
  apply (rule_tac q=q in br_step.intros)
  apply simp
  apply (simp only: br'_rcm_aux2)
  apply (simp only: br'_rcm_aux3)
  done
  

lemma br'_initial_abs: "br'_α`(br'_initial δ) = {br_initial δ}"
  apply (force simp add: br_initial_def br'_α_def
               elim: br'_initial.cases 
               intro: br'_initial.intros)
  done

lemma br'_cond_abs: "Σbr'_cond  (br'_α Σ)  br_cond"
  by (cases Σ) 
     (simp add: br'_cond_def br_cond_def br'_α_def image_Collect 
                br'_algo_def br_algo_def)

lemma bre'_cond_abs: "Σbre'_cond Qi  (br'_α Σ)bre_cond Qi"
  by (cases Σ) (simp add: bre'_cond_def bre_cond_def br'_α_def image_Collect 
                          bre'_algo_def bre_algo_def)

lemma br'_invar_abs: "br'_α`br'_invar δ  br_invar δ"
  by (auto simp add: br'_invar_def)

theorem br'_pref_br: "wa_precise_refine (br'_algo δ) (br_algo δ) br'_α"
  apply unfold_locales
  apply (simp_all add: br'_algo_def br_algo_def)
  apply (simp_all add: br'_cond_abs br'_step_abs br'_invar_abs br'_initial_abs)
  done

interpretation br'_pref: wa_precise_refine "br'_algo δ" "br_algo δ" "br'_α" 
  using br'_pref_br .

theorem br'_while_algo: 
  "finite δ  while_algo (br'_algo δ)"
  apply (rule br'_pref.wa_intro)
  apply (simp add: br_while_algo)
  apply (simp_all add: br'_algo_def br_algo_def)
  apply (simp add: br'_invar_def)
  apply (erule (3) br'_step_invar)
  apply (simp add: br'_invar_initial)
  done

lemma fst_br'_α: "fst (br'_α s) = fst s" by (cases s) (simp add: br'_α_def)

lemmas br'_invar_final = 
  br'_pref.transfer_correctness[OF br_invar_final, unfolded fst_br'_α]

theorem bre'_pref_br: "wa_precise_refine (bre'_algo Qi δ) (bre_algo Qi δ) br'_α"
  apply unfold_locales
  apply (simp_all add: bre'_algo_def bre_algo_def)
  apply (simp_all add: bre'_cond_abs br'_step_abs br'_invar_abs br'_initial_abs)
  done

interpretation bre'_pref: 
  wa_precise_refine "bre'_algo Qi δ" "bre_algo Qi δ" "br'_α" 
  using bre'_pref_br .

theorem bre'_while_algo: 
  "finite δ  while_algo (bre'_algo Qi δ)"
  apply (rule bre'_pref.wa_intro)
  apply (simp add: bre_while_algo)
  apply (simp_all add: bre'_algo_def bre_algo_def)
  apply (simp add: br'_invar_def)
  apply (erule (3) br'_step_invar)
  apply (simp add: br'_invar_initial)
  done

lemmas bre'_invar_final = 
  bre'_pref.transfer_correctness[OF bre_invar_final, unfolded fst_br'_α]

text_raw ‹\paragraph{Implementing a Step}›
text ‹
  In this paragraph, it is shown how to implement a step of the br'-algorithm 
  by iteration over the rules that have the discovered state on their RHS.
›

definition br'_inner_step 
  :: "('Q,'L) ta_rule  ('Q,'L) br'_state  ('Q,'L) br'_state" 
  where
  "br'_inner_step == λr (Q,W,rcm). let c=the (rcm r) in (
    if c1 then insert (lhs r) Q else Q,
    if c1  (lhs r)  Q then insert (lhs r) W else W,
    rcm ( r  (c-(1::nat)))
  )
"

definition br'_inner_invar 
  :: "('Q,'L) ta_rule set  'Q  ('Q,'L) br'_state 
       ('Q,'L) ta_rule set  ('Q,'L) br'_state  bool" 
  where
  "br'_inner_invar rules q == λ(Q,W,rcm) it (Q',W',rcm'). 
    Q' = Q  { lhs r | r. rrules-it  the (rcm r)  1 }  
    W' = (W-{q})  ({ lhs r | r. rrules-it  the (rcm r)  1 } - Q)  
    (r. rcm' r = (if rrules-it then Some (the (rcm r) - 1) else rcm r))
  "

lemma br'_inner_invar_imp_final: 
  " qW; br'_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) {} Σ'  
      ((Q,W,rcm),Σ')  br'_step δ"
  apply (unfold br'_inner_invar_def)
  apply auto
  apply (rule br'_step.intros)
  apply assumption
  apply auto
  done

lemma br'_inner_invar_step: 
  " qW; br'_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) it Σ'; 
     rit; it{rδ. qset (rhsq r)} 
     br'_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) 
                         (it-{r}) (br'_inner_step r Σ')
  "
  apply (cases Σ', simp)
  apply (unfold br'_inner_invar_def br'_inner_step_def Let_def)
  apply auto
  done

lemma br'_inner_invar_initial: 
  " qW   br'_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) 
                               {rδ. qset (rhsq r)} (Q,W-{q},rcm)"
  apply (simp add: br'_inner_invar_def)
  apply auto
  done

lemma br'_inner_step_proof:
  fixes αs :: "  ('Q,'L) br'_state"
  fixes cstep :: "('Q,'L) ta_rule    "
  fixes Σh :: ""
  fixes cinvar :: "('Q,'L) ta_rule set    bool"

  assumes iterable_set: "set_iteratei α invar iteratei"
  assumes invar_initial: "cinvar {rδ. qset (rhsq r)} Σh"
  assumes invar_step: 
    "!!it r Σ.  rit; it  {rδ. qset (rhsq r)}; cinvar it Σ  
                  cinvar (it-{r}) (cstep r Σ)"
  assumes step_desc: 
    "!!it r Σ.  rit; it{rδ. qset (rhsq r)}; cinvar it Σ  
                  αs (cstep r Σ) = br'_inner_step r (αs Σ)"
  assumes it_set_desc: "invar it_set" "α it_set = {rδ. qset (rhsq r)}"

  assumes QIW[simp]: "qW"

  assumes Σ_desc[simp]: "αs Σ = (Q,W,rcm)"
  assumes Σh_desc[simp]: "αs Σh = (Q,W-{q},rcm)"

  shows "(αs Σ, αs (iteratei it_set (λ_. True) cstep Σh))br'_step δ"
proof -
  interpret set_iteratei α invar iteratei by fact

  show ?thesis
    apply (rule_tac 
      I="λit Σ. cinvar it Σ 
                 br'_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) 
                                  it (αs Σ)" 
      in iterate_rule_P)
    apply (simp_all 
      add: it_set_desc invar_initial br'_inner_invar_initial invar_step 
           step_desc br'_inner_invar_step)
    apply (rule br'_inner_invar_imp_final)
    apply (rule QIW)
    apply simp
    done
qed


text_raw ‹\paragraph{Computing Witnesses}›
text ‹
  The algorithm is now refined further, such that it stores, for each discovered
  state, a witness for non-emptiness, i.e. a tree that is accepted with the
  discovered state.
›

― ‹A map from states to trees has the witness-property, if it maps states to 
    trees that are accepted with that state:›
definition "witness_prop δ m == q t. m q = Some t  accs δ t q"

― ‹Construct a witness for the LHS of a rule, provided that the map contains 
    witnesses for all states on the RHS:›
definition construct_witness 
  :: "('Q  'L tree)  ('Q,'L) ta_rule  'L tree"
  where 
  "construct_witness Q r == NODE (rhsl r) (List.map (λq. the (Q q)) (rhsq r))"

lemma witness_propD: "witness_prop δ m; m q = Some t  accs δ t q" 
  by (auto simp add: witness_prop_def)

lemma construct_witness_correct: 
  " witness_prop δ Q; rδ; set (rhsq r)  dom Q  
     accs δ (construct_witness Q r) (lhs r)"
  apply (unfold construct_witness_def witness_prop_def)
  apply (cases r)
  apply simp
  apply (erule accs.intros)
  apply (auto dest: nth_mem)
  done

lemma construct_witness_eq: 
  " Q |` set (rhsq r) = Q' |` set (rhsq r)   
    construct_witness Q r = construct_witness Q' r"
  apply (unfold construct_witness_def)
  apply auto
  apply (subgoal_tac "Q x = Q' x")
  apply (simp)
  apply (drule_tac x=x in fun_cong)
  apply auto
  done

text ‹
  The set of discovered states is refined by a map from discovered states to 
  their witnesses:
›
type_synonym ('Q,'L) brw_state = "('Q'L tree) × 'Q set × (('Q,'L) ta_rule  nat)"

definition brw_α :: "('Q,'L) brw_state  ('Q,'L) br'_state" 
  where "brw_α = (λ(Q,W,rcm). (dom Q,W,rcm))"

definition brw_invar_add :: "('Q,'L) ta_rule set  ('Q,'L) brw_state set"
  where "brw_invar_add δ == {(Q,W,rcm). witness_prop δ Q}"

definition "brw_invar δ == brw_invar_add δ  {s. brw_α s  br'_invar δ}"

(* TODO:
    This step description does not allow full flexibility, because
    we may want to construct new witnesses from other witnesses constructed 
    in the same step!
    
    However, if we say t = construct_witness Q' r, may we run into cyclicity 
    problems, where a cycle of witnesses
    may witness itself?. Hmm? As these cyclic witnesses would have to
    be infinite, they cannot exist?

    But, if we use a BFS search strategy, the current step description will 
    compute minimal depth witnesses.
    The argumentation is, that:
      Initially, all witnesses of depth 1 (definitely minimal) are discovered
      A witness of depth n has children of length < n
      The states that are initially on the workset are all those with 
      witnesses of depth 1. Thus,
      after they have been processed, all states with witnesses of depth 2 have
      been discovered. This argument can be iterated inductively.
*)
inductive_set brw_step 
  :: "('Q,'L) ta_rule set  (('Q,'L) brw_state × ('Q,'L) brw_state) set" 
  for δ where
  " 
     qW;
     dsqr = { rδ. q  set (rhsq r)  the (rcm r)  1 };
     dom Q' = dom Q  lhs`dsqr;
     !!q t. Q' q = Some t  Q q = Some t 
                               (rdsqr. q=lhs r  t=construct_witness Q r);
     W' = (W-{q})  (lhs`dsqr - dom Q);
     !!r. rδ  rcm' r = ( if q  set (rhsq r) then 
                               Some (the (rcm r) - 1) 
                             else rcm r
                           )
     ((Q,W,rcm),(Q',W',rcm'))  brw_step δ"


definition brw_cond :: "'Q set  ('Q,'L) brw_state set" 
  where "brw_cond Qi == {(Q,W,rcm). W{}  (Qidom Q={})}"

inductive_set brw_iq :: "('Q,'L) ta_rule set  ('Q  'L tree) set" 
  for δ where 
  " 
    q t. Q q = Some t  (rδ. rhsq r = []  q = lhs r 
                                   t = NODE (rhsl r) []);
    rδ. rhsq r = []  Q (lhs r)  None
     Q  brw_iq δ"

inductive_set brw_initial :: "('Q,'L) ta_rule set  ('Q,'L) brw_state set" 
  for δ where
  " !!r. rδ  rcm r = Some (card (set (rhsq r))); Qbrw_iq δ  
      (Q, br_iq δ, rcm)brw_initial δ"

definition "brw_algo Qi δ == 
  wa_cond=brw_cond Qi,
  wa_step = brw_step δ,
  wa_initial = brw_initial δ,
  wa_invar = brw_invar δ
"

lemma brw_cond_abs: "Σbrw_cond Qi  (brw_α Σ)bre'_cond Qi"
  apply (cases Σ)
  apply (simp add: brw_cond_def bre'_cond_def brw_α_def)
  done

lemma brw_initial_abs: "Σbrw_initial δ  brw_α Σ  br'_initial δ"
  apply (cases Σ, simp)
  apply (erule brw_initial.cases)
  apply (erule brw_iq.cases)
  apply (auto simp add: brw_α_def)
  apply (subgoal_tac "dom Qa = br_iq δ")
  apply simp
  apply (rule br'_initial.intros)
  apply auto [1]
  apply (force simp add: br_iq_def)
  done


lemma brw_invar_initial: "brw_initial δ  brw_invar_add δ"
  apply safe
  apply (unfold brw_invar_add_def)
  apply (auto simp add: witness_prop_def)
  apply (erule brw_initial.cases)
  apply (erule brw_iq.cases)
  apply auto
proof goal_cases
  case prems: (1 q t rcm Q)
  from prems(3)[rule_format, OF prems(1)] obtain r where 
    [simp]: "rδ" "rhsq r = []" "q=lhs r" "t=NODE (rhsl r) []" 
    by blast
  have RF[simplified]: "r=((lhs r)  (rhsl r) (rhsq r))" by (cases r) simp
  show ?case 
    apply (simp)
    apply (rule accs.intros)
    apply (subst RF[symmetric])
    apply auto
    done
qed
    
lemma brw_step_abs:
  " (Σ,Σ')brw_step δ   (brw_α Σ, brw_α Σ')br'_step δ"
  apply (cases Σ, cases Σ', simp)
  apply (erule brw_step.cases)
  apply (simp add: brw_α_def)
  apply hypsubst
  apply (rule br'_step.intros)
  apply assumption
  apply auto
  done

lemma brw_step_invar:
  assumes FIN[simp]: "finite δ"
  assumes INV: "Σbrw_invar_add δ" and BR'INV: "brw_α Σ  br'_invar δ"
  assumes STEP: "(Σ,Σ')  brw_step δ"
  shows "Σ'brw_invar_add δ"
proof -
  obtain Q W rcm Q' W' rcm' where 
    [simp]: "Σ=(Q,W,rcm)" "Σ'=(Q',W',rcm')" 
    by (cases Σ, cases Σ') force

  from INV have WP: "witness_prop δ Q" 
    by (simp_all add: brw_invar_add_def)

  obtain qw dsqr where SPROPS:
    "dsqr = {r  δ. qw  set (rhsq r)  the (rcm r)  1}"
    "qwW"
    "dom Q' = dom Q  lhs ` dsqr"
    "!!q t. Q' q = Some t  Q q = Some t 
                               (rdsqr. q=lhs r  t=construct_witness Q r)"
    by (auto intro: brw_step.cases[OF STEP[simplified]])
  from br'_rcm_aux'[OF BR'INV[unfolded brw_α_def, simplified] SPROPS(2)] have 
    DSQR_ALT: "dsqr = {r  δ. qw  set (rhsq r) 
                               set (rhsq r)  dom Q - (W - {qw})}" 
    by (simp add: SPROPS(1))
  have "witness_prop δ Q'" 
  proof (unfold witness_prop_def, safe)
    fix q t
    assume A: "Q' q = Some t"

    from SPROPS(4)[OF A] have 
      "Q q = Some t  (rdsqr. q = lhs r  t = construct_witness Q r)" .
    moreover {
      assume C: "Q q = Some t"
      from witness_propD[OF WP, OF C] have "accs δ t q" .
    } moreover {
      fix r
      assume "rdsqr" and [simp]: "q=lhs r" "t=construct_witness Q r"
      from rdsqr have 1: "rδ" "set (rhsq r)  dom Q" 
        by (auto simp add: DSQR_ALT)
      from construct_witness_correct[OF WP 1] have "accs δ t q" by simp
    } ultimately show "accs δ t q" by blast
  qed
  thus ?thesis by (simp add: brw_invar_add_def)
qed
      
theorem brw_pref_bre': "wa_precise_refine (brw_algo Qi δ) (bre'_algo Qi δ) brw_α"
  apply (unfold_locales)
  apply (simp_all add: brw_algo_def bre'_algo_def)
  apply (auto simp add: brw_cond_abs brw_step_abs brw_initial_abs brw_invar_def)
  done

interpretation brw_pref: 
  wa_precise_refine "brw_algo Qi δ" "bre'_algo Qi δ" "brw_α" 
  using brw_pref_bre' .

theorem brw_while_algo: "finite δ  while_algo (brw_algo Qi δ)"
  apply (rule brw_pref.wa_intro)
  apply (simp add: bre'_while_algo)
  apply (simp_all add: brw_algo_def bre'_algo_def)
  apply (simp add: brw_invar_def)
  apply (auto intro: brw_step_invar simp add: brw_invar_initial)
  done

lemma fst_brw_α: "fst (brw_α s) = dom (fst s)" 
  by (cases s) (simp add: brw_α_def)

theorem brw_invar_final: 
  "sc. sc  wa_invar (brw_algo Qi δ)  sc  wa_cond (brw_algo Qi δ) 
     (Qi  dom (fst sc) = {}) = (Qi  b_accessible δ = {}) 
         (witness_prop δ (fst sc))"
  apply (intro conjI allI impI)
  using brw_pref.transfer_correctness[OF bre'_invar_final, unfolded fst_brw_α] 
    apply blast
  apply (auto simp add: brw_algo_def brw_invar_def brw_invar_add_def)
  done
     

text_raw ‹\paragraph{Implementing a Step}›
inductive_set brw_inner_step 
  :: "('Q,'L) ta_rule  (('Q,'L) brw_state × ('Q,'L) brw_state) set" 
  for r where
  "  c = the (rcm r); Σ = (Q,W,rcm); Σ'=(Q',W',rcm');
     if c1  (lhs r)  dom Q then 
       Q' = Q(lhs r  construct_witness Q r) 
     else Q' = Q;
     if c1  (lhs r)  dom Q then 
       W' = insert (lhs r) W 
     else W' = W;
     rcm' = rcm ( r  (c-(1::nat)))
     (Σ,Σ')brw_inner_step r"

definition brw_inner_invar 
  :: "('Q,'L) ta_rule set  'Q  ('Q,'L) brw_state  ('Q,'L) ta_rule set 
       ('Q,'L) brw_state  bool" 
  where
  "brw_inner_invar rules q == λ(Q,W,rcm) it (Q',W',rcm').
    (br'_inner_invar rules q (brw_α (Q,W,rcm)) it (brw_α (Q',W',rcm'))   
    (Q'|`dom Q = Q)  
    (let dsqr = { rrules - it. the (rcm r)  1 } in
      (q t. Q' q = Some t  (Q q = Some t 
            (Q q = None  (rdsqr. q=lhs r  t=construct_witness Q r))
                                )
      )))
  "

lemma brw_inner_step_abs: 
  "(Σ,Σ')brw_inner_step r  br'_inner_step r (brw_α Σ) = brw_α Σ'"
  apply (erule brw_inner_step.cases)
  apply (unfold br'_inner_step_def brw_α_def Let_def)
  apply auto
  done


lemma brw_inner_invar_imp_final: 
  " qW; brw_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) {} Σ'  
     ((Q,W,rcm),Σ')  brw_step δ"
  apply (unfold brw_inner_invar_def br'_inner_invar_def brw_α_def)
  apply (auto simp add: Let_def)
  apply (rule brw_step.intros)
  apply assumption
  apply (rule refl)
  apply auto
  done


lemma brw_inner_invar_step: 
  assumes INVI: "(Q,W,rcm)brw_invar δ"
  assumes A: "qW" "rit" "it{rδ. qset (rhsq r)}" 
  assumes INVH: "brw_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) it Σh"
  assumes STEP: "(Σh,Σ')brw_inner_step r" 
  shows "brw_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) (it-{r}) Σ'"
proof -
  from INVI have BR'_INV: "(dom Q,W,rcm)br'_invar δ"
    by (simp add: brw_invar_def brw_α_def)

  obtain c Qh Wh rcmh Q' W' rcm' where
    SIGMAF[simp]: "Σh=(Qh,Wh,rcmh)" "Σ'=(Q',W',rcm')" and
    CF[simp]: "c = the (rcmh r)" and
    SF: "if c1  (lhs r)  dom Qh then 
           Q' = Qh(lhs r  (construct_witness Qh r)) 
         else Q' = Qh"

        "if c1  (lhs r)  dom Qh then 
           W' = insert (lhs r) Wh 
         else W' = Wh"

        "rcm' = rcmh ( r  (c-(1::nat)))"
    by (blast intro: brw_inner_step.cases[OF STEP])
  let ?rules = "{rδ. qset (rhsq r)}"
  let ?dsqr = "λit. { r?rules - it. the (rcm r)  1 }"
  from INVH have INVHF:
    "br'_inner_invar ?rules q (dom Q, W-{q}, rcm) (it) (dom Qh,Wh,rcmh)"
    "Qh|`dom Q = Q"
    "(q t. Qh q = Some t  (Q q = Some t 
          (Q q = None  (r?dsqr it. q=lhs r  t=construct_witness Q r))
                               )
     )"
    by (auto simp add: brw_inner_invar_def Let_def brw_α_def)
  from INVHF(1)[unfolded br'_inner_invar_def] have INV'HF:
    "dom Qh = dom Q  lhs`?dsqr it"
    "(r. rcmh r = (if r  ?rules - it then 
                      Some (the (rcm r) - 1) 
                    else rcm r))"
    by auto
  from brw_inner_step_abs[OF STEP] 
       br'_inner_invar_step[OF A(1) INVHF(1) A(2,3)] have 
    G1: "br'_inner_invar ?rules q (dom Q, W-{q}, rcm) (it-{r}) (dom Q',W',rcm')"
    by (simp add: brw_α_def)
  moreover have
    "(q t. Q' q = Some t  (Q q = Some t 
         ( Q q = None 
             (r?dsqr (it-{r}). q=lhs r  t=construct_witness Q r)
           ) 
                              ) 
     )" (is ?G1)

    "Q'|`dom Q = Q" (is ?G2)
  proof -
    {
      assume C: "¬ c1  lhs r  dom Qh"
      with SF have "Q'=Qh" by auto
      with INVHF(2,3) have ?G1 ?G2 by auto
    } moreover {
      assume C: "c1" "lhs r dom Qh"
      with SF have Q'F: "Q'=Qh(lhs r  (construct_witness Qh r))" by auto
      from C(2) INVHF(2) INV'HF(1) have G2: ?G2 by (auto simp add: Q'F)
      from C(1) INV'HF A have 
        RI: "r?dsqr (it-{r})" and 
        DSS: "dom Q  dom Qh" 
        by (auto)
      from br'_rcm_aux'[OF BR'_INV A(1)] RI have 
        RDQ: "set (rhsq r)  dom Q" 
        by auto
      with INVHF(2) have "Qh |` set (rhsq r) = Q |` set (rhsq r)"
        by (blast intro: restrict_map_subset_eq)
      hence [simp]: "construct_witness Qh r = construct_witness Q r" 
        by (blast dest: construct_witness_eq)

      from DSS C(2) have [simp]: "Q (lhs r) = None" "Qh (lhs r) = None" by auto
      have G1: ?G1
      proof (intro allI impI, goal_cases)
        case prems: (1 q t)
        {
          assume [simp]: "q=lhs r"
          from prems Q'F have [simp]: "t = (construct_witness Qh r)" by simp
          from RI have ?case by auto
        } moreover {
          assume "qlhs r"
          with Q'F prems have "Qh q = Some t" by auto
          with INVHF(3) have ?case by auto
        } ultimately show ?case by blast
      qed
      note G1 G2
    } ultimately show ?G1 ?G2 by blast+
  qed
  ultimately show ?thesis
    by (unfold brw_inner_invar_def Let_def brw_α_def) auto
qed


lemma brw_inner_invar_initial: 
  "qW  brw_inner_invar {rδ. qset (rhsq r)} q (Q,W-{q},rcm) 
                             {rδ. qset (rhsq r)} (Q,W-{q},rcm)"
  by (simp add: brw_inner_invar_def br'_inner_invar_initial brw_α_def)

theorem brw_inner_step_proof:
  fixes αs :: "  ('Q,'L) brw_state"
  fixes cstep :: "('Q,'L) ta_rule    "
  fixes Σh :: ""
  fixes cinvar :: "('Q,'L) ta_rule set    bool"

  assumes set_iterate: "set_iteratei α invar iteratei"
  assumes invar_start: "(αs Σ)brw_invar δ"
  assumes invar_initial: "cinvar {rδ. qset (rhsq r)} Σh"
  assumes invar_step: 
    "!!it r Σ.  rit; it  {rδ. qset (rhsq r)}; cinvar it Σ  
                 cinvar (it-{r}) (cstep r Σ)"
  assumes step_desc: 
    "!!it r Σ.  rit; it{rδ. qset (rhsq r)}; cinvar it Σ  
                 (αs Σ, αs (cstep r Σ))  brw_inner_step r"
  assumes it_set_desc: "invar it_set" "α it_set = {rδ. qset (rhsq r)}"

  assumes QIW[simp]: "qW"

  assumes Σ_desc[simp]: "αs Σ = (Q,W,rcm)"
  assumes Σh_desc[simp]: "αs Σh = (Q,W-{q},rcm)"

  shows "(αs Σ, αs (iteratei it_set (λ_. True) cstep Σh))brw_step δ"
proof -
  interpret set_iteratei α invar iteratei by fact

  show ?thesis
    apply (rule_tac 
      I="λit Σ. cinvar it Σ  brw_inner_invar {rδ. qset (rhsq r)} q 
                                                (Q,W-{q},rcm) it (αs Σ)" 
      in iterate_rule_P)
    apply (auto 
      simp add: it_set_desc invar_initial brw_inner_invar_initial invar_step 
                step_desc brw_inner_invar_step[OF invar_start[simplified]] 
                brw_inner_invar_imp_final[OF QIW])
    done
qed

subsection ‹Product Automaton›

text ‹
  The forward-reduced product automaton can be described as a state-space
  exploration problem. 

  In this section, the DFS-algorithm for state-space exploration 
  (cf. Theory~@{theory Collections_Examples.Exploration} in the Isabelle Collections Framework) is refined to compute the product automaton.
›

type_synonym ('Q1,'Q2,'L) frp_state = 
  "('Q1×'Q2) set × ('Q1×'Q2) list × (('Q1×'Q2),'L) ta_rule set"

definition frp_α :: "('Q1,'Q2,'L) frp_state  ('Q1×'Q2) dfs_state"
  where "frp_α S == let (Q,W,δ)=S in (Q, W)"

definition "frp_invar_add δ1 δ2 == 
  { (Q,W,δd). δd = { r. rδ_prod δ1 δ2  lhs r  Q - set W} }"

definition frp_invar 
  :: "('Q1, 'L) tree_automaton_rec  ('Q2, 'L) tree_automaton_rec 
       ('Q1,'Q2,'L) frp_state set"
  where "frp_invar T1 T2 == 
  frp_invar_add (ta_rules T1) (ta_rules T2) 
   { s. frp_α s  dfs_invar (ta_initial T1 × ta_initial T2) 
                              (f_succ (δ_prod (ta_rules T1) (ta_rules T2))) }"

inductive_set frp_step 
  :: "('Q1,'L) ta_rule set  ('Q2,'L) ta_rule set 
       (('Q1,'Q2,'L) frp_state × ('Q1,'Q2,'L) frp_state) set" 
  for δ1 δ2 where
  " W=(q1,q2)#Wtl;
     distinct Wn;
     set Wn = f_succ (δ_prod δ1 δ2) `` {(q1,q2)} - Q;
     W'=Wn@Wtl;
     Q'=Q  f_succ (δ_prod δ1 δ2) `` {(q1,q2)};
     δd'=δd  {rδ_prod δ1 δ2. lhs r = (q1,q2) }
    ((Q,W,δd),(Q',W',δd'))frp_step δ1 δ2"

inductive_set frp_initial :: "'Q1 set  'Q2 set  ('Q1,'Q2,'L) frp_state set"
  for Q10 Q20 where 
  " distinct W; set W = Q10×Q20   (Q10×Q20,W,{})  frp_initial Q10 Q20"

definition frp_cond :: "('Q1,'Q2,'L) frp_state set" where
  "frp_cond == {(Q,W,δd). W[]}"

definition "frp_algo T1 T2 == 
  wa_cond = frp_cond,
  wa_step = frp_step (ta_rules T1) (ta_rules T2),
  wa_initial = frp_initial (ta_initial T1) (ta_initial T2),
  wa_invar = frp_invar T1 T2
"

  ― ‹The algorithm refines the DFS-algorithm›
theorem frp_pref_dfs: 
  "wa_precise_refine (frp_algo T1 T2) 
     (dfs_algo (ta_initial T1 × ta_initial T2) 
               (f_succ (δ_prod (ta_rules T1) (ta_rules T2))))
     frp_α"
  apply unfold_locales
  apply (auto simp add: frp_algo_def frp_α_def frp_cond_def dfs_algo_def 
                        dfs_cond_def frp_invar_def
    elim!: frp_step.cases frp_initial.cases
    intro: dfs_step.intros dfs_initial.intros
  )
  done 

interpretation frp_ref: wa_precise_refine "(frp_algo T1 T2)"
                  "(dfs_algo (ta_initial T1 × ta_initial T2) 
                             (f_succ (δ_prod (ta_rules T1) (ta_rules T2))))"
                  "frp_α" using frp_pref_dfs .

― ‹The algorithm is a well-defined while-algorithm›
theorem frp_while_algo:
  assumes TA: "tree_automaton T1" 
              "tree_automaton T2"
  shows "while_algo (frp_algo T1 T2)"
proof -
  interpret t1: tree_automaton T1 by fact
  interpret t2: tree_automaton T2 by fact

  have finite: "finite ((f_succ (δ_prod (ta_rules T1) (ta_rules T2)))* 
               `` (ta_initial T1 × ta_initial T2))"
  proof -
    have "((f_succ (δ_prod (ta_rules T1) (ta_rules T2)))* 
               `` (ta_initial T1 × ta_initial T2)) 
           ((ta_initial T1 × ta_initial T2) 
              δ_states (δ_prod (ta_rules T1) (ta_rules T2)))"
      apply rule
      apply (drule f_accessible_subset[unfolded f_accessible_def])
      apply auto
      done
    moreover have "finite "
      by auto
    ultimately show ?thesis by (simp add: finite_subset)
  qed

  show ?thesis
    apply (rule frp_ref.wa_intro)
    apply (rule dfs_while_algo[OF finite])
    apply (simp add: frp_algo_def dfs_algo_def frp_invar_def)
    apply (auto simp add: dfs_algo_def frp_algo_def frp_α_def 
                          dfs_α_def frp_invar_add_def dfs_invar_def 
                          dfs_invar_add_def sse_invar_def 
                elim!: frp_step.cases) [1]
    apply (force simp add: frp_algo_def frp_invar_add_def 
                 elim!: frp_initial.cases)
    done
qed

(* unused
lemma f_succ_adv: 
  "⟦lhs r ∈ (f_succ δ)* `` Q0; r∈δ⟧ ⟹ set (rhsq r) ⊆ (f_succ δ)* `` Q0"
  by (case_tac r) (auto dest: rtrancl_into_rtrancl intro: f_succ.intros)
*)

― ‹If the algorithm terminates, the forward reduced product automaton 
    can be constructed from the result›
theorem frp_inv_final:
  "s. swa_invar (frp_algo T1 T2)  swa_cond (frp_algo T1 T2)
        (case s of (Q,W,δd)  
              ta_initial = ta_initial T1 × ta_initial T2, 
               ta_rules = δd 
              = ta_fwd_reduce (ta_prod T1 T2))"
  apply (intro allI impI)
  apply (case_tac s)
  apply simp
  apply (simp add: ta_reduce_def ta_prod_def frp_algo_def)
proof -
  fix Q W δd
  assume A: "(Q,W,δd)frp_invar T1 T2  (Q,W,δd)frp_cond"

  from frp_ref.transfer_correctness[OF dfs_invar_final, 
                                    unfolded frp_algo_def, simplified, 
                                    rule_format, OF A]
  have [simp]: "Q = f_accessible (δ_prod (ta_rules T1) (ta_rules T2)) 
                                 (ta_initial T1 × ta_initial T2)"
    by (simp add: f_accessible_def dfs_α_def frp_α_def)

  from A show "δd = reduce_rules 
    (δ_prod (ta_rules T1) (ta_rules T2)) 
    (f_accessible (δ_prod (ta_rules T1) (ta_rules T2)) 
                  (ta_initial T1 × ta_initial T2))"
    apply (auto simp add: reduce_rules_def f_accessible_def frp_invar_def 
                          frp_invar_add_def frp_α_def frp_cond_def)
    apply (case_tac x) 
    apply (auto dest: rtrancl_into_rtrancl intro: f_succ.intros)
    done
qed


end