Theory Provenance_Labels
theory Provenance_Labels
imports Label_Algebra
begin
text ‹
This theory instantiates labels by sets of natural-number assumption indices.
Application and pairing combine provenance by union, implication introduction
removes the discharged assumption label, and disjunction elimination records
the analysed disjunction together with the branch dependencies that survive
discharge.
›
type_synonym prov = "nat set"
interpretation provenance: label_structure
where app = "λ(S::prov) T. S ∪ T"
and lam = "λ(S::prov) T. T - S"
and pair = "λ(S::prov) T. S ∪ T"
and fst_l = "λ(S::prov). S"
and snd_l = "λ(S::prov). S"
and abort = "λ(S::prov). S"
and inl = "λ(S::prov). S"
and inr = "λ(S::prov). S"
and cases = "λ(S::prov) (M::prov) (N::prov) (P::prov) (Q::prov).
S ∪ (N - M) ∪ (Q - P)"
.
definition provenance_erase_label :: "prov ⇒ unit" where
"provenance_erase_label S = ()"
definition provenance_lift_label :: "(prov, 'a) lfm list ⇒ 'a fm ⇒ prov" where
"provenance_lift_label Γ A =
(SOME S. provenance.lderives Γ (S, A))"
interpretation provenance: label_algebra
where app = "λ(S::prov) T. S ∪ T"
and lam = "λ(S::prov) T. T - S"
and pair = "λ(S::prov) T. S ∪ T"
and fst_l = "λ(S::prov). S"
and snd_l = "λ(S::prov). S"
and abort = "λ(S::prov). S"
and inl = "λ(S::prov). S"
and inr = "λ(S::prov). S"
and cases = "λ(S::prov) (M::prov) (N::prov) (P::prov) (Q::prov).
S ∪ (N - M) ∪ (Q - P)"
and lderives = provenance.lderives
and erase_label = provenance_erase_label
and lift_label = provenance_lift_label
proof
fix S :: prov
show "provenance_erase_label S = ()"
by (simp add: provenance_erase_label_def)
next
fix Γ :: "(prov, 'a) lfm list" and x :: "(prov, 'a) lfm"
assume "provenance.lderives Γ x"
then show "erase_ctx Γ ⊢ erase_lfm x"
by (rule provenance.erasure_sound)
next
fix Γ :: "(prov, 'a) lfm list" and A :: "'a fm"
assume ordinary: "erase_ctx Γ ⊢ A"
have "∃S. provenance.lderives Γ (S, A)"
by (rule provenance.lifting_general[OF ordinary])
then show "provenance.lderives Γ (provenance_lift_label Γ A, A)"
unfolding provenance_lift_label_def by (rule someI_ex)
qed
fun indexed :: "nat ⇒ 'a fm list ⇒ (prov × 'a fm) list" where
"indexed n [] = []"
| "indexed n (A # Γ) = ({n}, A) # indexed (Suc n) Γ"
definition ctx_prov :: "(prov, 'a) lfm list ⇒ prov" where
"ctx_prov Γ = ⋃(fst ` set Γ)"
lemma ctx_prov_Cons [simp]:
"ctx_prov ((M, A) # Γ) = M ∪ ctx_prov Γ"
unfolding ctx_prov_def
by auto
lemma erase_ctx_indexed [simp]:
"erase_ctx (indexed n Γ) = Γ"
by (induction Γ arbitrary: n) auto
lemma finite_ctx_prov_indexed [simp]:
"finite (ctx_prov (indexed n Γ))"
by (induction Γ arbitrary: n) (auto simp: ctx_prov_def)
definition filter_indexed_by :: "nat set ⇒ 'a fm list ⇒ 'a fm list" where
"filter_indexed_by S Γ =
map snd (filter (λ(i, A). i ∈ S) (zip [0..<length Γ] Γ))"
lemma filter_indexed_by_mono:
assumes "S ⊆ T"
shows "set (filter_indexed_by S Γ) ⊆ set (filter_indexed_by T Γ)"
using assms
unfolding filter_indexed_by_def
by auto
lemma filter_indexed_by_subset_ctx:
shows "set (filter_indexed_by S Γ) ⊆ set Γ"
unfolding filter_indexed_by_def
by (auto simp: in_set_zip)
lemma filter_indexed_by_empty [simp]:
"filter_indexed_by {} Γ = []"
unfolding filter_indexed_by_def
by auto
lemma filter_indexed_by_union:
"set (filter_indexed_by (S ∪ T) Γ) =
set (filter_indexed_by S Γ) ∪ set (filter_indexed_by T Γ)"
unfolding filter_indexed_by_def
by auto
definition filter_labeled_by :: "prov ⇒ (prov × 'a fm) list ⇒ 'a fm list" where
"filter_labeled_by S Γ =
map snd (filter (λ(M, A). M ∩ S ≠ {}) Γ)"
definition nonempty_prov_ctx :: "(prov × 'a fm) list ⇒ bool" where
"nonempty_prov_ctx Γ ⟷ (∀x ∈ set Γ. fst x ≠ {})"
lemma nonempty_prov_ctx_Cons [simp]:
"nonempty_prov_ctx ((S, A) # Γ) ⟷ S ≠ {} ∧ nonempty_prov_ctx Γ"
unfolding nonempty_prov_ctx_def
by auto
lemma nonempty_prov_ctx_indexed [simp]:
"nonempty_prov_ctx (indexed n Γ)"
by (induction Γ arbitrary: n) (auto simp: nonempty_prov_ctx_def)
lemma filter_labeled_by_mono:
assumes "S ⊆ T"
shows "set (filter_labeled_by S Γ) ⊆ set (filter_labeled_by T Γ)"
using assms
unfolding filter_labeled_by_def
by auto
lemma filter_labeled_by_union_left:
"set (filter_labeled_by S Γ) ⊆ set (filter_labeled_by (S ∪ T) Γ)"
by (rule filter_labeled_by_mono) auto
lemma filter_labeled_by_union_right:
"set (filter_labeled_by T Γ) ⊆ set (filter_labeled_by (S ∪ T) Γ)"
by (rule filter_labeled_by_mono) auto
lemma ctx_prov_contains_label:
assumes "(M, A) ∈ set Γ"
shows "M ⊆ ctx_prov Γ"
using assms
unfolding ctx_prov_def
by auto
lemma filter_labeled_by_minus_fresh:
assumes "M ∩ ctx_prov Γ = {}"
shows "set (filter_labeled_by N Γ) ⊆ set (filter_labeled_by (N - M) Γ)"
proof
fix A
assume "A ∈ set (filter_labeled_by N Γ)"
then obtain y where y_in: "y ∈ set Γ"
and y_used: "(case y of (L, B) ⇒ L ∩ N ≠ {})"
and y_snd: "snd y = A"
unfolding filter_labeled_by_def
by auto
obtain L B where y: "y = (L, B)"
by (cases y)
have in_ctx: "(L, A) ∈ set Γ"
using y y_in y_snd by auto
have used: "L ∩ N ≠ {}"
using y y_used by simp
have "L ∩ M = {}"
using assms ctx_prov_contains_label[OF in_ctx] by auto
with used have "L ∩ (N - M) ≠ {}"
by auto
with in_ctx have "(L, A) ∈
set (filter (λ(K, B). K ∩ (N - M) ≠ {}) Γ)"
by auto
then show "A ∈ set (filter_labeled_by (N - M) Γ)"
unfolding filter_labeled_by_def by force
qed
lemma filter_labeled_by_cons_minus_subset:
assumes "M ∩ ctx_prov Γ = {}"
shows "set (filter_labeled_by N ((M, A) # Γ)) ⊆
set (A # filter_labeled_by (N - M) Γ)"
proof -
have "set (filter_labeled_by N ((M, A) # Γ)) ⊆
insert A (set (filter_labeled_by N Γ))"
unfolding filter_labeled_by_def
by auto
also have "… ⊆ set (A # filter_labeled_by (N - M) Γ)"
using filter_labeled_by_minus_fresh[OF assms] by auto
finally show ?thesis .
qed
lemma filter_labeled_by_cons_minus_mono_subset:
assumes "M ∩ ctx_prov Γ = {}" and "N - M ⊆ U"
shows "set (filter_labeled_by N ((M, A) # Γ)) ⊆
set (A # filter_labeled_by U Γ)"
proof -
have "set (filter_labeled_by N ((M, A) # Γ)) ⊆
set (A # filter_labeled_by (N - M) Γ)"
using assms(1) by (rule filter_labeled_by_cons_minus_subset)
moreover have "set (filter_labeled_by (N - M) Γ) ⊆
set (filter_labeled_by U Γ)"
using assms(2) by (rule filter_labeled_by_mono)
ultimately show ?thesis
by auto
qed
lemma filter_labeled_by_indexed_upt:
"filter_labeled_by S (indexed n Γ) =
map snd (filter (λ(i, A). i ∈ S) (zip [n..<n + length Γ] Γ))"
proof (induction Γ arbitrary: n)
case Nil
then show ?case
by (simp add: filter_labeled_by_def)
next
case (Cons A Γ)
have upt: "[n..<n + length (A # Γ)] =
n # [Suc n..<Suc n + length Γ]"
proof -
have "[n..<n + length (A # Γ)] = n # [Suc n..<n + length (A # Γ)]"
by (rule upt_conv_Cons) simp
also have "… = n # [Suc n..<Suc n + length Γ]"
by simp
finally show ?thesis .
qed
show ?case
using Cons.IH[of "Suc n"] upt
by (auto simp: filter_labeled_by_def)
qed
lemma filter_labeled_by_indexed_0:
"filter_labeled_by S (indexed 0 Γ) = filter_indexed_by S Γ"
by (simp add: filter_labeled_by_indexed_upt filter_indexed_by_def)
inductive prov_safe :: "(prov × 'a fm) list ⇒ prov × 'a fm ⇒ bool"
("_ ⊢P _" [50, 50] 50)
where
PAssm:
"x ∈ set Γ ⟹ Γ ⊢P x"
| PBotE:
"Γ ⊢P (S, Bot) ⟹ Γ ⊢P (S, A)"
| PImpI:
"(M, A) # Γ ⊢P (N, B) ⟹
M ∩ ctx_prov Γ = {} ⟹
M ≠ {} ⟹
Γ ⊢P (N - M, Imp A B)"
| PImpE:
"Γ ⊢P (S, Imp A B) ⟹
Γ ⊢P (T, A) ⟹
Γ ⊢P (S ∪ T, B)"
| PConI:
"Γ ⊢P (S, A) ⟹
Γ ⊢P (T, B) ⟹
Γ ⊢P (S ∪ T, Con A B)"
| PConE1:
"Γ ⊢P (S, Con A B) ⟹ Γ ⊢P (S, A)"
| PConE2:
"Γ ⊢P (S, Con A B) ⟹ Γ ⊢P (S, B)"
| PDisI1:
"Γ ⊢P (S, A) ⟹ Γ ⊢P (S, Dis A B)"
| PDisI2:
"Γ ⊢P (S, B) ⟹ Γ ⊢P (S, Dis A B)"
| PDisE:
"Γ ⊢P (S, Dis A B) ⟹
(M, A) # Γ ⊢P (N, C) ⟹
(P, B) # Γ ⊢P (Q, C) ⟹
M ∩ ctx_prov Γ = {} ⟹ M ≠ {} ⟹
P ∩ ctx_prov Γ = {} ⟹ P ≠ {} ⟹
M ∩ P = {} ⟹
Γ ⊢P (S ∪ (N - M) ∪ (Q - P), C)"
lemma provenance_labels_in_context:
assumes "provenance.lderives Γ x"
shows "fst x ⊆ ctx_prov Γ"
using assms
by (induction rule: provenance.lderives.induct) (auto simp: ctx_prov_def)
lemma ctx_prov_indexed_bound:
assumes "i ∈ ctx_prov (indexed n Γ)"
shows "i < n + length Γ"
using assms
proof (induction Γ arbitrary: n i)
case Nil
then show ?case
by (simp add: ctx_prov_def)
next
case (Cons A Γ)
then consider "i = n" | "i ∈ ctx_prov (indexed (Suc n) Γ)"
by (auto simp: ctx_prov_def)
then show ?case
proof cases
case 1
then show ?thesis
by simp
next
case 2
then have "i < Suc n + length Γ"
by (rule Cons.IH)
then show ?thesis
by simp
qed
qed
theorem provenance_overapproximates_dependencies:
assumes "provenance.lderives (indexed 0 Γ0) (S, A)"
shows "∀i. i ∈ S ⟶ i < length Γ0"
proof
fix i
show "i ∈ S ⟶ i < length Γ0"
proof
assume "i ∈ S"
moreover have "S ⊆ ctx_prov (indexed 0 Γ0)"
using provenance_labels_in_context[OF assms] by simp
ultimately have "i ∈ ctx_prov (indexed 0 Γ0)"
by auto
then show "i < length Γ0"
using ctx_prov_indexed_bound[of i 0 Γ0] by simp
qed
qed
lemma prov_safe_implies_lderives:
assumes "Γ ⊢P x"
shows "provenance.lderives Γ x"
using assms
by (induction rule: prov_safe.induct)
(auto intro: provenance.LAssm provenance.LBotE provenance.LImpI
provenance.LImpE provenance.LConI provenance.LConE1 provenance.LConE2
provenance.LDisI1 provenance.LDisI2 provenance.LDisE)
lemma provenance_drop_unused_general:
assumes "Γ ⊢P x" and "nonempty_prov_ctx Γ"
shows "filter_labeled_by (fst x) Γ ⊢ snd x"
using assms
proof (induction rule: prov_safe.induct)
case (PAssm x Γ)
obtain M A where x: "x = (M, A)"
by (cases x)
then have in_ctx: "(M, A) ∈ set Γ"
using PAssm by simp
moreover have "M ≠ {}"
using PAssm x
unfolding nonempty_prov_ctx_def filter_labeled_by_def
by auto
then have "M ∩ M ≠ {}"
by auto
ultimately have "(M, A) ∈
set (filter (λ(L, B). L ∩ M ≠ {}) Γ)"
by auto
then have "A ∈ set (filter_labeled_by M Γ)"
unfolding filter_labeled_by_def by force
then show ?case
using x by (auto intro: derives.Assm)
next
case (PBotE Γ S A)
then show ?case
by (auto intro: derives.BotE)
next
case (PImpI M A Γ N B)
have ne: "nonempty_prov_ctx ((M, A) # Γ)"
using PImpI by simp
have body: "filter_labeled_by N ((M, A) # Γ) ⊢ B"
using PImpI.IH[OF ne] by simp
have sub: "set (filter_labeled_by N ((M, A) # Γ)) ⊆
set (A # filter_labeled_by (N - M) Γ)"
using PImpI by (intro filter_labeled_by_cons_minus_subset) auto
have "filter_labeled_by (N - M) Γ ⊢ Imp A B"
proof (rule derives.ImpI)
show "A # filter_labeled_by (N - M) Γ ⊢ B"
by (rule weakening[OF body sub])
qed
then show ?case
by simp
next
case (PImpE Γ S A B T)
have imp0: "filter_labeled_by S Γ ⊢ Imp A B"
using PImpE.IH(1)[OF PImpE.prems] by simp
have arg0: "filter_labeled_by T Γ ⊢ A"
using PImpE.IH(2)[OF PImpE.prems] by simp
have imp: "filter_labeled_by (S ∪ T) Γ ⊢ Imp A B"
by (rule weakening[OF imp0 filter_labeled_by_union_left])
have arg: "filter_labeled_by (S ∪ T) Γ ⊢ A"
by (rule weakening[OF arg0 filter_labeled_by_union_right])
have "filter_labeled_by (S ∪ T) Γ ⊢ B"
by (rule derives.ImpE[OF imp arg])
then show ?case
by simp
next
case (PConI Γ S A T B)
have left0: "filter_labeled_by S Γ ⊢ A"
using PConI.IH(1)[OF PConI.prems] by simp
have right0: "filter_labeled_by T Γ ⊢ B"
using PConI.IH(2)[OF PConI.prems] by simp
have left: "filter_labeled_by (S ∪ T) Γ ⊢ A"
by (rule weakening[OF left0 filter_labeled_by_union_left])
have right: "filter_labeled_by (S ∪ T) Γ ⊢ B"
by (rule weakening[OF right0 filter_labeled_by_union_right])
have "filter_labeled_by (S ∪ T) Γ ⊢ Con A B"
by (rule derives.ConI[OF left right])
then show ?case
by simp
next
case (PConE1 Γ S A B)
then show ?case
by (auto intro: derives.ConE1)
next
case (PConE2 Γ S A B)
then show ?case
by (auto intro: derives.ConE2)
next
case (PDisI1 Γ S A B)
then show ?case
by (auto intro: derives.DisI1)
next
case (PDisI2 Γ S B A)
then show ?case
by (auto intro: derives.DisI2)
next
case (PDisE Γ S A B M N C P Q)
let ?U = "S ∪ (N - M) ∪ (Q - P)"
have ne_left: "nonempty_prov_ctx ((M, A) # Γ)"
using PDisE by simp
have ne_right: "nonempty_prov_ctx ((P, B) # Γ)"
using PDisE by simp
have disj0: "filter_labeled_by S Γ ⊢ Dis A B"
using PDisE.IH(1)[OF PDisE.prems] by simp
have left0: "filter_labeled_by N ((M, A) # Γ) ⊢ C"
using PDisE.IH(2)[OF ne_left] by simp
have right0: "filter_labeled_by Q ((P, B) # Γ) ⊢ C"
using PDisE.IH(3)[OF ne_right] by simp
have disj_sub: "set (filter_labeled_by S Γ) ⊆
set (filter_labeled_by ?U Γ)"
by (rule filter_labeled_by_mono) auto
have disj: "filter_labeled_by ?U Γ ⊢ Dis A B"
by (rule weakening[OF disj0 disj_sub])
have left_sub: "set (filter_labeled_by N ((M, A) # Γ)) ⊆
set (A # filter_labeled_by ?U Γ)"
using PDisE
by (intro filter_labeled_by_cons_minus_mono_subset) auto
have left: "A # filter_labeled_by ?U Γ ⊢ C"
by (rule weakening[OF left0 left_sub])
have right_sub: "set (filter_labeled_by Q ((P, B) # Γ)) ⊆
set (B # filter_labeled_by ?U Γ)"
using PDisE
by (intro filter_labeled_by_cons_minus_mono_subset) auto
have right: "B # filter_labeled_by ?U Γ ⊢ C"
by (rule weakening[OF right0 right_sub])
have "filter_labeled_by ?U Γ ⊢ C"
by (rule derives.DisE[OF disj left right])
then show ?case
by simp
qed
theorem provenance_drop_unused:
assumes "indexed 0 Γ0 ⊢P (S, A)"
shows "filter_indexed_by S Γ0 ⊢ A"
proof -
have "filter_labeled_by S (indexed 0 Γ0) ⊢ A"
using provenance_drop_unused_general[OF assms] by simp
then show ?thesis
by (simp add: filter_labeled_by_indexed_0)
qed
lemma fresh_nat:
assumes "finite F"
obtains i :: nat where "i ∉ F"
proof -
have "∃i :: nat. i ∉ F"
using assms ex_new_if_finite[OF infinite_UNIV_nat] by blast
then show ?thesis
using that by blast
qed
lemma fresh_nat2:
assumes "finite F"
obtains i j :: nat where "i ∉ F" and "j ∉ F" and "i ≠ j"
proof -
obtain i where i: "i ∉ F"
using assms by (rule fresh_nat)
from assms have "finite (insert i F)"
by simp
then obtain j where j: "j ∉ insert i F"
by (rule fresh_nat)
from j have "j ∉ F" and "i ≠ j"
by auto
with i show ?thesis
by (rule that)
qed
lemma ordinary_admits_safe_provenance_labeled:
assumes "Δ ⊢ A"
and "erase_ctx Γ = Δ"
and "nonempty_prov_ctx Γ"
and "finite (ctx_prov Γ)"
shows "∃S. Γ ⊢P (S, A) ∧ S ⊆ ctx_prov Γ"
using assms
proof (induction arbitrary: Γ rule: derives.induct)
case (Assm A Δ)
then have "A ∈ set (erase_ctx Γ)"
by simp
then obtain S where in_ctx: "(S, A) ∈ set Γ"
by (rule erase_ctx_mem_label)
have "Γ ⊢P (S, A)"
using in_ctx by (rule prov_safe.PAssm)
moreover have "S ⊆ ctx_prov Γ"
using in_ctx by (rule ctx_prov_contains_label)
ultimately show ?case
by blast
next
case (BotE Δ A)
then obtain S where deriv: "Γ ⊢P (S, Bot)"
and sub: "S ⊆ ctx_prov Γ"
by blast
have "Γ ⊢P (S, A)"
by (rule prov_safe.PBotE[OF deriv])
with sub show ?case
by blast
next
case (ImpI A Δ B)
obtain i where fresh: "i ∉ ctx_prov Γ"
using ImpI.prems(3) by (rule fresh_nat)
let ?M = "{i}"
have erase: "erase_ctx ((?M, A) # Γ) = A # Δ"
using ImpI.prems(1) by simp
have nonempty: "nonempty_prov_ctx ((?M, A) # Γ)"
using ImpI.prems(2) by simp
have finite: "finite (ctx_prov ((?M, A) # Γ))"
using ImpI.prems(3) by simp
obtain N where body: "(?M, A) # Γ ⊢P (N, B)"
and sub_body: "N ⊆ ctx_prov ((?M, A) # Γ)"
using ImpI.IH[OF erase nonempty finite] by blast
have deriv: "Γ ⊢P (N - ?M, Imp A B)"
by (rule prov_safe.PImpI[OF body]) (use fresh in auto)
have "N - ?M ⊆ ctx_prov Γ"
using sub_body fresh by auto
with deriv show ?case
by blast
next
case (ImpE Δ A B)
obtain S where imp: "Γ ⊢P (S, Imp A B)"
and sub_imp: "S ⊆ ctx_prov Γ"
using ImpE.IH(1)[OF ImpE.prems] by blast
obtain T where arg: "Γ ⊢P (T, A)"
and sub_arg: "T ⊆ ctx_prov Γ"
using ImpE.IH(2)[OF ImpE.prems] by blast
have "Γ ⊢P (S ∪ T, B)"
by (rule prov_safe.PImpE[OF imp arg])
moreover have "S ∪ T ⊆ ctx_prov Γ"
using sub_imp sub_arg by auto
ultimately show ?case
by blast
next
case (ConI Δ A B)
obtain S where left: "Γ ⊢P (S, A)"
and sub_left: "S ⊆ ctx_prov Γ"
using ConI.IH(1)[OF ConI.prems] by blast
obtain T where right: "Γ ⊢P (T, B)"
and sub_right: "T ⊆ ctx_prov Γ"
using ConI.IH(2)[OF ConI.prems] by blast
have "Γ ⊢P (S ∪ T, Con A B)"
by (rule prov_safe.PConI[OF left right])
moreover have "S ∪ T ⊆ ctx_prov Γ"
using sub_left sub_right by auto
ultimately show ?case
by blast
next
case (ConE1 Δ A B)
then obtain S where deriv: "Γ ⊢P (S, Con A B)"
and sub: "S ⊆ ctx_prov Γ"
by blast
have "Γ ⊢P (S, A)"
by (rule prov_safe.PConE1[OF deriv])
with sub show ?case
by blast
next
case (ConE2 Δ A B)
then obtain S where deriv: "Γ ⊢P (S, Con A B)"
and sub: "S ⊆ ctx_prov Γ"
by blast
have "Γ ⊢P (S, B)"
by (rule prov_safe.PConE2[OF deriv])
with sub show ?case
by blast
next
case (DisI1 Δ A B)
then obtain S where deriv: "Γ ⊢P (S, A)"
and sub: "S ⊆ ctx_prov Γ"
by blast
have "Γ ⊢P (S, Dis A B)"
by (rule prov_safe.PDisI1[OF deriv])
with sub show ?case
by blast
next
case (DisI2 Δ B A)
then obtain S where deriv: "Γ ⊢P (S, B)"
and sub: "S ⊆ ctx_prov Γ"
by blast
have "Γ ⊢P (S, Dis A B)"
by (rule prov_safe.PDisI2[OF deriv])
with sub show ?case
by blast
next
case (DisE Δ A B C)
obtain i j where fresh_i: "i ∉ ctx_prov Γ"
and fresh_j: "j ∉ ctx_prov Γ"
and neq: "i ≠ j"
using DisE.prems(3) by (rule fresh_nat2)
let ?M = "{i}"
let ?P = "{j}"
obtain S where disj: "Γ ⊢P (S, Dis A B)"
and sub_disj: "S ⊆ ctx_prov Γ"
using DisE.IH(1)[OF DisE.prems] by blast
have erase_left: "erase_ctx ((?M, A) # Γ) = A # Δ"
using DisE.prems(1) by simp
have nonempty_left: "nonempty_prov_ctx ((?M, A) # Γ)"
using DisE.prems(2) by simp
have finite_left: "finite (ctx_prov ((?M, A) # Γ))"
using DisE.prems(3) by simp
obtain N where left: "(?M, A) # Γ ⊢P (N, C)"
and sub_left: "N ⊆ ctx_prov ((?M, A) # Γ)"
using DisE.IH(2)[OF erase_left nonempty_left finite_left] by blast
have erase_right: "erase_ctx ((?P, B) # Γ) = B # Δ"
using DisE.prems(1) by simp
have nonempty_right: "nonempty_prov_ctx ((?P, B) # Γ)"
using DisE.prems(2) by simp
have finite_right: "finite (ctx_prov ((?P, B) # Γ))"
using DisE.prems(3) by simp
obtain Q where right: "(?P, B) # Γ ⊢P (Q, C)"
and sub_right: "Q ⊆ ctx_prov ((?P, B) # Γ)"
using DisE.IH(3)[OF erase_right nonempty_right finite_right] by blast
have deriv: "Γ ⊢P (S ∪ (N - ?M) ∪ (Q - ?P), C)"
by (rule prov_safe.PDisE[OF disj left right]) (use fresh_i fresh_j neq in auto)
have "S ∪ (N - ?M) ∪ (Q - ?P) ⊆ ctx_prov Γ"
using sub_disj sub_left sub_right fresh_i fresh_j by auto
with deriv show ?case
by blast
qed
theorem ordinary_admits_safe_provenance:
assumes "Γ ⊢ A"
shows "∃S. (indexed 0 Γ ⊢P (S, A))
∧ S ⊆ {0..<length Γ}
∧ set (filter_indexed_by S Γ) ⊆ set Γ"
proof -
obtain S where deriv: "indexed 0 Γ ⊢P (S, A)"
and sub_ctx: "S ⊆ ctx_prov (indexed 0 Γ)"
using ordinary_admits_safe_provenance_labeled[OF assms, of "indexed 0 Γ"]
by simp blast
have sub_indices: "S ⊆ {0..<length Γ}"
proof
fix i
assume "i ∈ S"
then have "i ∈ ctx_prov (indexed 0 Γ)"
using sub_ctx by auto
then have "i < length Γ"
using ctx_prov_indexed_bound[of i 0 Γ] by simp
then show "i ∈ {0..<length Γ}"
by simp
qed
have "set (filter_indexed_by S Γ) ⊆ set Γ"
by (rule filter_indexed_by_subset_ctx)
with deriv sub_indices show ?thesis
by blast
qed
corollary ordinary_admits_tight_provenance:
assumes "Γ ⊢ A"
shows "∃S. (indexed 0 Γ ⊢P (S, A))
∧ S ⊆ {0..<length Γ}
∧ filter_indexed_by S Γ ⊢ A"
proof -
obtain S where deriv: "indexed 0 Γ ⊢P (S, A)"
and sub: "S ⊆ {0..<length Γ}"
using ordinary_admits_safe_provenance[OF assms] by blast
have "filter_indexed_by S Γ ⊢ A"
by (rule provenance_drop_unused[OF deriv])
with deriv sub show ?thesis
by blast
qed
theorem provenance_completeness:
shows "(Γ ⊢ A) ⟷
(∃S. (indexed 0 Γ ⊢P (S, A)) ∧ filter_indexed_by S Γ ⊢ A)"
proof
assume "Γ ⊢ A"
then show "∃S. (indexed 0 Γ ⊢P (S, A)) ∧ filter_indexed_by S Γ ⊢ A"
using ordinary_admits_tight_provenance by blast
next
assume "∃S. (indexed 0 Γ ⊢P (S, A)) ∧ filter_indexed_by S Γ ⊢ A"
then obtain S where deriv: "indexed 0 Γ ⊢P (S, A)"
by blast
have "filter_indexed_by S Γ ⊢ A"
by (rule provenance_drop_unused[OF deriv])
moreover have "set (filter_indexed_by S Γ) ⊆ set Γ"
by (rule filter_indexed_by_subset_ctx)
ultimately show "Γ ⊢ A"
by (rule weakening)
qed
end