Theory Regex_Proof_System
theory Regex_Proof_System
imports Regex
begin
context begin
qualified inductive
SAT :: "(nat ⇒ 'a ⇒ bool) ⇒ nat ⇒ nat ⇒ 'a Regex.regex ⇒ bool"
for sat where
STest: "i = j ⟹ sat i x ⟹ SAT sat i j (Regex.Test x)"
| SSkip: "j = i + n ⟹ SAT sat i j (Regex.Skip n)"
| SPlusL: "SAT sat i j r ⟹ SAT sat i j (Regex.Plus r s)"
| SPlusR: "SAT sat i j s ⟹ SAT sat i j (Regex.Plus r s)"
| STimes: "SAT sat i k r ⟹ SAT sat k j s ⟹ SAT sat i j (Regex.Times r s)"
| SStar_eps: "i = j ⟹ SAT sat i j (Regex.Star r)"
| SStar: "i < j ⟹ (∃zs. xs = i # zs @ [j]) ⟹
∀k ∈ {0 ..< length xs - 1}. xs ! k < xs ! (Suc k) ⟹
∀k ∈ {0 ..< length xs - 1}. SAT sat (xs ! k) (xs ! (Suc k)) r ⟹
SAT sat i j (Regex.Star r)"
lemma SAT_mono[mono]:
assumes "X ≤ Y"
shows "SAT X ≤ SAT Y"
unfolding le_fun_def le_bool_def
proof safe
fix i j r
assume "SAT X i j r"
then show "SAT Y i j r"
by (induct i j r rule: SAT.induct) (use assms in ‹auto 0 3 intro: SAT.intros›)
qed
abbreviation "rm S ≡ {(i, j) ∈ S. i < j}"
qualified inductive
VIO :: "(nat ⇒ 'a ⇒ bool) ⇒ nat ⇒ nat ⇒ 'a Regex.regex ⇒ bool"
for vio where
VSkip: "j ≠ i + n ⟹ VIO vio i j (Regex.Skip n)"
| VTest: "i = j ⟹ vio i x ⟹ VIO vio i j (Regex.Test x)"
| VTest_neq: "i ≠ j ⟹ VIO vio i j (Regex.Test x)"
| VPlus: "VIO vio i j r ⟹ VIO vio i j s ⟹ VIO vio i j (Regex.Plus r s)"
| VTimes: "∀k ∈ {i .. j}. VIO vio i k r ∨ VIO vio k j s ⟹ VIO vio i j (Regex.Times r s)"
| VStar: "i < j ⟹ i ∈ S ⟹ j ∈ T ⟹ S ∪ T = {i .. j} ⟹ S ∩ T = {} ⟹
∀(s, t) ∈ rm (S × T). VIO vio s t r ⟹ VIO vio i j (Regex.Star r)"
| VStar_gt: "i > j ⟹ VIO vio i j (Regex.Star r)"
lemma VIO_mono[mono]:
assumes "X ≤ Y"
shows "VIO X ≤ VIO Y"
unfolding le_fun_def le_bool_def
proof safe
fix i j r
assume "VIO X i j r"
then show "VIO Y i j r"
by (induct i j r rule: VIO.induct) (use assms in ‹auto 5 3 intro: VIO.intros›)
qed
inductive chain :: "('a ⇒ 'a ⇒ bool) ⇒ 'a list ⇒ bool" for R :: "'a ⇒ 'a ⇒ bool" where
chain_singleton: "chain R [x]"
| chain_cons: "chain R (y # xs) ⟹ R x y ⟹ chain R (x # y # xs)"
lemma
chain_Nil[simp]: "¬ chain R []" and
chain_not_Nil: "chain R xs ⟹ xs ≠ []"
by (auto elim: chain.cases)
lemma chain_rtranclp: "chain R xs ⟹ R⇧*⇧* (hd xs) (last xs)"
by (induct xs rule: chain.induct) auto
lemma chain_append:
assumes "chain R xs" "chain R ys" "R (last xs) (hd ys)"
shows "chain R (xs @ ys)"
using assms
proof (induct xs arbitrary: ys rule: chain.induct)
case (chain_singleton x)
then show ?case by (cases ys) (auto intro: chain.intros)
qed (auto intro: chain.intros)
lemma tranclp_imp_exists_finite_chain_list:
"R⇧+⇧+ x y ⟹ ∃xs. chain R (x # xs @ [y])"
proof (induct rule: tranclp.induct)
case (r_into_trancl x y)
then have "chain R (x # [] @ [y])"
by (auto intro: chain.intros)
then show ?case
by blast
next
case (trancl_into_trancl x y z)
note rstar_xy = this(1) and ih = this(2) and r_yz = this(3)
obtain xs where xs: "chain R (x # xs @ [y])" using ih by blast
define ys where "ys = xs @ [y]"
have "chain R (x # ys @ [z])"
unfolding ys_def using r_yz chain_append[OF xs chain_singleton, of z] by auto
then show ?case by blast
qed
lemma chain_pairwise:
"chain R xs ⟹ Suc i < length xs ⟹ R (xs ! i) (xs ! Suc i)"
by (induct xs arbitrary: i rule: chain.induct)
(force simp: nth_Cons' not_le Suc_less_eq2 elim: chain.cases)+
lemma chain_sorted_remdups:
"chain R xs ⟹ (⋀x y. R x y ⟹ x ≤ y) ⟹ sorted xs ∧ chain R (remdups xs)"
proof (induct xs rule: chain.induct)
case (chain_cons y xs x)
then show ?case
using sorted_remdups[of xs] set_remdups[of xs] eq_iff[of y "hd (remdups xs)"]
by (cases "remdups xs"; cases "y = hd (remdups xs)")
(auto intro!: chain.intros intro: order_trans elim: chain.cases)
qed (auto intro: chain.intros)
lemma sorted_remdups: "sorted xs ⟹ sorted_wrt (<) (remdups xs)"
by (induct xs) (auto dest: le_neq_trans)
lemma remdups_sorted_start_end:
"sorted (i # xs @ [j]) ⟹ i ≠ j ⟹
remdups (i # xs @ [j]) = i # remdups (removeAll j (removeAll i xs)) @ [j]"
by (induct xs) auto
lemma tranclp_to_list:
fixes R :: "'a :: linorder ⇒ 'a ⇒ bool"
assumes "R⇧+⇧+ i j" "i ≠ j" "⋀x y. R x y ⟹ x ≤ y"
obtains xs zs where "xs = i # zs @ [j]"
"∀k ∈ {0 ..< length xs - 1}. xs ! k < xs ! (Suc k) ∧ R (xs ! k) (xs ! (Suc k))"
proof atomize_elim
from ‹R⇧+⇧+ i j› obtain zs where "chain R (i # zs @ [j])"
using tranclp_imp_exists_finite_chain_list by fast
then have zs: "sorted (i # zs @ [j])" "chain R (remdups (i # zs @ [j]))"
using chain_sorted_remdups assms(3) by blast+
then have sorted_wrt: "sorted_wrt (<) (remdups (i # zs @ [j]))"
using sorted_remdups by blast
let ?zs = "remdups (removeAll j (removeAll i zs))"
from zs sorted_wrt have "chain R (i # ?zs @ [j])" "sorted_wrt (<) (i # ?zs @ [j])"
using remdups_sorted_start_end[of i zs j] assms(2) by auto
then show "∃xs zs. xs = i # zs @ [j] ∧
(∀k∈{0..<length xs - 1}. xs ! k < xs ! Suc k ∧ R (xs ! k) (xs ! Suc k))"
by (subst ex_comm, unfold simp_thms, intro exI[of _ ?zs])
(auto 0 3 dest: chain_pairwise simp del: remdups.simps
simp: sorted_wrt_iff_nth_less)
qed
abbreviation match_rel where
"match_rel test r xs k ≡ (xs ! k < xs ! (Suc k) ∧ Regex.match test r (xs ! k) (xs ! (Suc k)))"
lemma list_to_chain:
"xs ≠ [] ⟹ ∀k ∈ {0 ..< length xs - 1}. R (xs ! k) (xs ! Suc k) ⟹ chain R xs"
proof (induct xs)
case (Cons a xs)
then show ?case
proof (cases xs)
case tail: (Cons b ys)
with Cons(2,3) show ?thesis
by (force intro!: chain.intros Cons(1)[unfolded tail])
qed (auto intro: chain.intros)
qed simp
lemma match_rel_list_to_tranclp:
"∃xs zs. xs = i # zs @ [j] ∧ (∀k ∈ {0 ..< length xs - 1}. match_rel test r xs k) ⟹ i ≠ j ⟹
(Regex.match test r)⇧+⇧+ i j"
using chain_rtranclp[OF list_to_chain, THEN rtranclpD, of "i # _ @ [j]" "Regex.match test r"]
by fastforce
lemma completeness_SAT:
"∀x ∈ Regex.atms r. ∀i. test i x ⟶ sat i x ⟹ Regex.match test r i j ⟹ SAT sat i j r"
proof (induct r arbitrary: i j)
case (Skip x)
then show ?case
by (auto intro: SAT.SSkip)
next
case (Test x)
then show ?case
by (auto intro: SAT.STest)
next
case (Plus r1 r2)
then show ?case
by (auto intro: SAT.SPlusL SPlusR)
next
case (Times r1 r2)
then obtain k where k_def: "k ∈ {i .. j} ∧ SAT sat i k r1 ∧ SAT sat k j r2"
using match_le by fastforce
then show ?case by (auto intro: SAT.STimes)
next
case (Star r)
then have "i = j ∨ (i ≠ j ∧ (Regex.match test r)⇧+⇧+ i j)"
using rtranclpD[of "Regex.match test r" i j] tranclpD[of "Regex.match test r" i j]
by auto
moreover
{
assume i_eq_j: "i = j"
then have "SAT sat i j (Regex.Star r)" by (auto intro: SAT.SStar_eps)
}
moreover
{
assume i_neq_j: "i ≠ j" and tranclp_ij: "(Regex.match test r)⇧+⇧+ i j"
then have i_less: "i < j" using Star
by (auto simp add: le_neq_implies_less match_rtranclp_le)
then obtain xs and zs where xs_def: "xs = i # zs @ [j] ∧ (∀k ∈ {0 ..< length xs - 1}. xs ! k < xs ! (Suc k) ∧ Regex.match test r (xs ! k) (xs ! (Suc k)))"
using tranclp_to_list[OF tranclp_ij i_neq_j match_le[of test r]] by auto
then have "SAT sat i j (Regex.Star r)" using i_less Star
by (auto intro: SAT.SStar)
}
ultimately show ?case by auto
qed
lemma completeness_VIO:
"∀x ∈ Regex.atms r. ∀i. ¬ test i x ⟶ vio i x ⟹ i ≤ j ⟹ ¬ Regex.match test r i j ⟹ VIO vio i j r"
proof (induct r arbitrary: i j)
case (Skip x)
then show ?case
by (auto intro: VIO.VSkip)
next
case (Test x)
then show ?case
by (auto intro: VIO.VTest VIO.VTest_neq)
next
case (Plus r1 r2)
then show ?case
by (auto intro: VIO.VPlus)
next
case (Times r1 r2)
then have "∀k ∈ {i .. j}. VIO vio i k r1 ∨ VIO vio k j r2"
by fastforce
then show ?case
by (auto intro: VIO.VTimes)
next
case (Star r)
define V where V_def: "V = {i .. j}"
define S where S_def: "S = {k ∈ V. (Regex.match test r)⇧*⇧* i k} ∪ {i}"
define T where T_def: "T = V - S"
from S_def V_def have j_notin_S: "j ∉ S" using Star
by auto
from S_def have i_in_S: "i ∈ S"
by auto
then have j_in_T: "j ∈ T" using j_notin_S V_def T_def Star(3)
by auto
from Star have nmatch_ij: "¬ (Regex.match test r)⇧*⇧* i j"
by auto
from S_def T_def V_def Star(3) have union_ST: "S ∪ T = {i .. j}"
by auto
from S_def T_def V_def Star(4) have inter_ST: "S ∩ T = {}"
by auto
with i_in_S j_in_T Star(3) have i_less_j: "i < j"
using le_eq_less_or_eq by blast
{
assume not_viost: "¬ (∀(s,t) ∈ rm (S × T). VIO vio s t r)"
then obtain s and t where st_def: "(s, t) ∈ rm (S × T) ∧ ¬ VIO vio s t r"
by auto
then have "Regex.match test r s t" using Star
by auto
then have "(Regex.match test r)⇧*⇧* i t" using st_def S_def
by auto
then have False using T_def st_def S_def
by auto
}
then have no_path: "∀(s,t) ∈ rm (S × T). VIO vio s t r"
by auto
then show ?case
by (auto intro: VIO.VStar[OF i_less_j i_in_S j_in_T union_ST inter_ST no_path])
qed
lemma soundness_SAT:
"∀x ∈ Regex.atms r. ∀i. sat i x ⟶ test i x ⟹ SAT sat i j r ⟹ Regex.match test r i j"
proof(induct r arbitrary: i j)
case (Skip x)
then show ?case using SAT.simps[of sat i j "Regex.Skip x"]
by auto
next
case (Test x)
then show ?case using SAT.simps[of sat i j "Regex.Test x"]
by auto
next
case (Plus r1 r2)
then show ?case using SAT.simps[of sat i j "Regex.Plus r1 r2"]
by auto
next
case (Times r1 r2)
then show ?case using SAT.simps[of sat i j "Regex.Times r1 r2"]
by fastforce
next
case (Star r)
then show ?case
proof(cases "i = j")
case True
then show ?thesis
by auto
next
case False
then obtain xs and zs where xs_form: "xs = i # zs @ [j]" and
xs_props: "∀k ∈ {0 ..< length xs - 1}. xs ! k < xs ! (Suc k) ∧ SAT sat (xs ! k) (xs ! (Suc k)) r"
using Star(3) SAT.simps[of sat i j "Regex.Star r"]
by blast
then have kmatch: "∀k ∈ {0 ..< length xs - 1}. Regex.match test r (xs ! k) (xs ! Suc k)"
using Star
by auto
then have ex_lists: "∃xs zs. xs = i # zs @ [j] ∧
(∀k ∈ {0 ..< length xs - 1}. xs ! k < xs ! (Suc k) ∧ Regex.match test r (xs ! k) (xs ! (Suc k)))"
using xs_form xs_props by auto
then have "(Regex.match test r)⇧+⇧+ i j"
using match_rel_list_to_tranclp[OF ex_lists False] by auto
then show ?thesis
by auto
qed
qed
lemma soundness_VIO:
"∀x ∈ Regex.atms r. ∀i. vio i x ⟶ ¬ test i x ⟹ i ≤ j ⟹ VIO vio i j r ⟹ ¬ Regex.match test r i j"
proof(induct r arbitrary: i j)
case (Skip x)
then show ?case using VIO.simps[of vio i j "Regex.Skip x"]
by auto
next
case (Test x)
then show ?case using VIO.simps[of vio i j "Regex.Test x"]
by auto
next
case (Plus r1 r2)
then show ?case using VIO.simps[of vio i j "Regex.Plus r1 r2"]
by auto
next
case (Times r1 r2)
then have kvio: "∀k ∈ {i .. j}. VIO vio i k r1 ∨ VIO vio k j r2"
using VIO.simps[of vio i j "Regex.Times r1 r2"]
by auto
have "∀k. Regex.match test r i k ∧ Regex.match test r k j ⟶ k ∈ {i .. j}"
using match_le
by auto
then show ?case using Times kvio match_le[of test]
unfolding Ball_def atLeastAtMost_iff match.simps regex.simps relcompp_apply
by (metis Un_iff)
next
case (Star r)
then obtain S and T where S_def: "i ∈ S" and T_def: "j ∈ T" and
ST_props: "S ∪ T = {i .. j} ∧ S ∩ T = {}" and
st_vio: "∀(s,t) ∈ rm (S × T). VIO vio s t r"
using Star(4) VIO.simps[of vio i j "Regex.Star r"]
by auto
then have nmatch_st: "∀(s,t) ∈ rm (S × T). ¬ Regex.match test r s t"
using Star
by auto
from S_def T_def ST_props have i_neq_j: "i ≠ j"
by auto
{
assume rtranclp_ij: "(Regex.match test r)⇧*⇧* i j"
then have tranclp_ij: "(Regex.match test r)⇧+⇧+ i j"
using rtranclpD[of "Regex.match test r" i j] i_neq_j
by auto
obtain xs and zs where xs_def: "xs = i # zs @ [j]" and
xs_prop: "∀k ∈ {0 ..< length xs - 1}. match_rel test r xs k"
using tranclp_to_list[OF tranclp_ij i_neq_j match_le[of test r]]
by auto
with S_def T_def ST_props have "∃k ∈ {0 ..< length xs - 1}. (xs ! k) ∈ S ∧ (xs ! (Suc k)) ∈ T"
proof (induction zs arbitrary: S T i j xs)
case Nil
then show ?case using S_def T_def xs_def
by auto
next
case (Cons a zs')
from Cons(2-6) have match: "Regex.match test r i a"
by force
show ?case
proof (cases "a ∈ T")
case True
then have "xs ! 0 ∈ S ∧ xs ! Suc 0 ∈ T" using S_def Cons
by (auto simp: xs_def)
then show ?thesis using S_def Cons(1)[of _ _ _ _ xs] Cons(2-5)
by force
next
case False
from Cons(5,6) have "chain (<) (i # (a # zs') @ [j])"
by (intro list_to_chain) auto
then have "sorted (i # (a # zs') @ [j])"
using chain_sorted_remdups[of "(<)" "i # (a # zs') @ [j]"]
by auto
then have "a ∈ {i .. j}"
by auto
with Cons(2-6) False have "∃k∈{0..<length (tl xs) - 1}. tl xs ! k ∈ {i ∈ S. a ≤ i} ∧ tl xs ! Suc k ∈ {i ∈ T. a ≤ i}"
by (intro Cons(1)[of a _ j]) (auto dest: bspec[of _ _ "Suc _"])
with Cons show ?thesis
by (auto intro: bexI[of _ "Suc _"])
qed
qed
then have False using nmatch_st xs_prop
by auto
}
then show ?case
by auto
qed
end
end