(* Title: Tree Automata Author:PeterLammich<peterdotlammichatuni-muenster.de> Maintainer:PeterLammich<peterdotlammichatuni-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) ⟷ a∈A ∧ 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: "q∈faccs δ n = accs δ n q" (is ?T1) "(map (faccs δ) ts = map (λt. { q . accs δ t q}) ts)" (is ?T2) proof - have"(∀q. q∈faccs δ 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: "q∈faccs δ n ==> accs δ n q" by (simp add: faccs_correct_aux) theorem faccs_correct2: "accs δ n q ==> q∈faccs δ n" by (simp add: faccs_correct_aux)
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"q∈b_accessible δ" thus"q∈Q" proof (induct rule: b_accessible.induct) fix q f qs assume BC: "(q→f qs)∈δ" "!!x. x∈set qs ==> x∈b_accessible δ" "!!x. x∈set qs ==> x∈Q" from bacc_step.intros[OF BC(1)] BC(3) have"q∈bacc_step δ Q"by auto with A show"q∈Q"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 "[ q∈W; 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≠{} ∧ (Qi∩Q={})}"
― ‹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). W⊆Q ∧ Q ⊆ b_accessible δ ∧ bacc_step δ (Q - W) ⊆ Q ∧ finite Q}"
― ‹Termination: Either a new state is added, or the workset decreases.› definition"br_termrel δ == ({(Q',Q). Q ⊂ Q' ∧ Q' ⊆ b_accessible δ}) <*lex*> finite_psubset"
― ‹Only accessible states are discovered› lemma br_dsq_ss: assumes A: "(Q,W)∈br_invar δ""W ≠ {}""q∈W" shows"br_dsq δ q (Q,W) ⊆ b_accessible δ" proof (rule subsetI) fix q' assume B: "q'∈br_dsq δ q (Q,W)" thenobtain r where
R: "q' = lhs r""r∈δ"and
S: "set (rhsq r) ⊆ (Q-(W-{q}))" by (unfold br_dsq_def) auto note S alsohave"(Q-(W-{q})) ⊆ b_accessible δ"using A(1,3) by (auto simp add: br_invar_def) finallyshow"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: "q∈W"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 moreoverfrom DSQSS A(2)[unfolded br_invar_def] have "Q' ⊆ b_accessible δ" by auto ultimatelyhave ?thesis by (auto simp add: br_termrel_def)
} ultimatelyshow ?thesis by blast qed
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)"
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: "q∈W" "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 "q∈set (rhsq r)") case False with A STEPF(4) have"rcm' r = rcm r"by auto moreoverfrom STEPF INV(3) False have "set (rhsq r) - (Q-W) = set (rhsq r) - (Q'-W')" by auto ultimatelyshow ?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 moreoverfrom 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 ultimatelyshow ?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 "q∈set (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
} ultimatelyshow ?thesis by (auto simp add: br'_invar_add_def) qed
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 c≤1 then insert (lhs r) Q else Q, if c≤1 ∧ (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. r∈rules-it ∧ the (rcm r) ≤ 1 } ∧ W' = (W-{q}) ∪ ({ lhs r | r. r∈rules-it ∧ the (rcm r) ≤ 1 } - Q) ∧ (∀r. rcm' r = (if r∈rules-it then Some (the (rcm r) - 1) else rcm r)) "
show ?thesis apply (rule_tac
I="λit Σ. cinvar it Σ ∧ br'_inner_invar {r∈δ. q∈set (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_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)"
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}" "qw∈W" "dom Q' = dom Q ∪ lhs ` dsqr" "!!q t. Q' q = Some t ==> Q q = Some t ∨ (∃r∈dsqr. 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 ∨ (∃r∈dsqr. 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"r∈dsqr"and [simp]: "q=lhs r""t=construct_witness Q r" from‹r∈dsqr›have1: "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
} ultimatelyshow"accs δ t q"by blast qed thus ?thesis by (simp add: brw_invar_add_def) qed
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 c≤1 ∧ (lhs r) ∉ dom Qh then Q' = Qh(lhs r ↦ (construct_witness Qh r)) else Q' = Qh"
"if c≤1 ∧ (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∈δ. q∈set (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) moreoverhave "(∀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: "¬ c≤1 ∨ lhs r ∈ dom Qh" with SF have"Q'=Qh"by auto with INVHF(2,3) have ?G1 ?G2 by auto
} moreover { assume C: "c≤1""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 ?caseby auto
} moreover { assume"q≠lhs r" with Q'F prems have"Qh q = Some t"by auto with INVHF(3) have ?caseby auto
} ultimatelyshow ?caseby blast qed note G1 G2
} ultimatelyshow ?G1 ?G2 by blast+ qed ultimatelyshow ?thesis by (unfold brw_inner_invar_def Let_def brw_α_def) auto qed
show ?thesis apply (rule_tac
I="λit Σ. cinvar it Σ ∧ brw_inner_invar {r∈δ. q∈set (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} }"
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"
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.